Android 下音频播放<一> MediaPlayer
来源:互联网 发布:网络投诉电话 编辑:程序博客网 时间:2024/05/17 03:21
最近在Android游戏开发中,需要处理WAV和OGG的播放。其中背景音乐需求为一路WAV或者OGG。在Android.media Package中。选中了MediaPlayer作为背景音乐的播放。
0. 简介:
android.media.MediaPlayer class用来控制播放Audio/Video 文件和流。(不光是文件,还支持流)
1. Playback状态机:
可以将播放文件和流看作状态机管理。下图详细描述了各状态以及如何在各状态间转移。
注:单箭头表示同步调用。双箭头表示异步调用。
现在详细分析每个状态以及状态间转移。
1.1:Idle状态:
当MediaPlayer object刚被使用new 创建,或者调用reset()后,此MediaPlayer object处于Idle状态。
两种方法进入Idle状态,有个细小却重要的区别:当程序在Idle状态错误的调用了类似getCurrentPosition(),GetDuration(),getVideoight(),setAudioStreamType(), setLooping(),setVolume(),pause(),start(),stop(),seekTo(),prepare()等方法。
如果MediaPlayer object刚被new 出来,处于idle状态。用户使用OnErrorListener.onError()注册的callback函数不会被内在palyer Engine调用,且状态不会发生改变,继续为idle.
如果是reset() 后处于idle状态,则注册的callback函数被调用。且MediaPlayer object会转为Error状态。
1.2:End状态:
当MediaPlayer object调用release() 后,它处于End 状态。
如果MediaPlayer object不再使用时,请立即调用release(),这样,内部player engine可以释放掉他们所占用的资源。 这类资源,不光包括内存资源,还包括Audio,Video硬件解码设备。
当用户进入End状态后,没有任何渠道去转回其它状态。
1.3:Initialized状态:
当MediaPlayer Object为Idle状态时,调用setDataSource(FileDescriptor), or setDataSource(String), or setDataSource(Context, Uri), or setDataSource(FileDescriptor, long, long)转变其状态到Initialized状态。
如果setDataSource()在非Idle状态调用,IllegalStateException会被抛出。
所以,setDataSource()时必须捕获IllegalArgumentException and IOException异常。
1.4:Prepared状态:
MediaPlayer Object 必须首先进入Prepared状态,之后才能开始start.
有两种方式进入Prepared状态:
调用prepare() 则以同步方式进入Prepared状态。当prepare()返回时,MediaPlayer Object 已经进入Prepared状态。
调用prepareAsync()则以异步方式进入Prepared状态。
当在错误状态调用prepare() or prepareAsync() ,则抛出异常IllegalStateException。
1.5: Started状态:
要播放,则需要调用start(),当start()返回successfully时,MediaPlayer Object则进入Started状态。
isPlaying()可以测试是否位于Started 状态。
在MediaPlayer Object处于Started状态时,调用start()没有任何效果。
1.6:Paused状态:
调用pause(),当其返回时,MediaoPlayer Object进入Paused状态。从started状态到pasued状态,Play Engine有缺陷。所以导致isPlaying()...
MediaPlayer进入Paused状态后,调用start()重新开始播放(Resume).但Position是从刚才暂停处开始播放,而不是从头。且状态变化为Started。
在Paused状态,再次调用pause()没有反应 。
1.7 Stop状态:
在Started,Paused,Prepared或者PlaybackCompleted状态,调用stop(),则进入Stopped状态。
在Stopped状态,MediaPlayer Object不能再次调用start()去播放,除非调用prepare()或prepareAsync()使其进入Prepared状态。
在Stopped状态下再次调用stop.无效。
1.8PlaybackCompleted状态 :
当Video/Audio播放完毕后,进入PlaybackCompleted模式。
但如果使用setLooping(true),则播放完毕后,立刻重新播放。且状态继续为started.
如果setLooping(false).播放完毕后,MediaPlayer Object进入PlaybackCompleted模式,并调用setOnCompletionListener(OnCompletionListener)注册的callback函数。
如在PlaybackCompleted状态下,调用start(),会进入started模式,并从头播放。
2. 回调机制:
MediaPlayer使用一些方法来设置回调函数,当发生某种特定情况时,内部palyer Engine会调用之。
使用方法,可以在稍后的例子中看到。
3. 播放指针:
可以调用seekTo()来调整当前播放指针。
下表列出了各种方法在哪些状态下调用合法,在哪些状态下非法以及导致的后果:
Error state.Error state.Error state.Error state.Error state.state. Calling this method in an invalid state transfers the object to the Error state.state. Calling this method in an invalid state throws an IllegalStateException.state. Calling this method in an invalid state throws an IllegalStateException.Error state.state. Calling this method in an invalid state throws an IllegalStateException.Error state.enerrstate. Calling this method in an invalid state transfers the object to the Error state.state. Calling this method in an invalid state transfers the object to the Error state.
例子程序如下:
MediaPlayer所支持格式:
这个问题,看到网上有不少人回答。但个人觉得回答并不正确。
MediaPlayer底层具体实现决定了所支持格式。毕竟JAVA层不太可能直接操作硬件去播放Video/Audio. 它也是通过JNI与底层C打交道播放Audio/Video. 那么底层的实现才是决定MediaPlayer支持格式的关键。
例如:Sam使用Hi3716C来测试,发现其底层是用HiPlayer来实现,支持WAV,OGG等。
但MTK5502平台,则只支持WAV.(可能OGG没来的及加入)
1. Playback状态机:
可以将播放文件和流看作状态机管理。下图详细描述了各状态以及如何在各状态间转移。
注:单箭头表示同步调用。双箭头表示异步调用。
现在详细分析每个状态以及状态间转移。
1.1:Idle状态:
当MediaPlayer object刚被使用new 创建,或者调用reset()后,此MediaPlayer object处于Idle状态。
两种方法进入Idle状态,有个细小却重要的区别:当程序在Idle状态错误的调用了类似getCurrentPosition(),GetDuration(),getVideoight(),setAudioStreamType(), setLooping(),setVolume(),pause(),start(),stop(),seekTo(),prepare()等方法。
如果MediaPlayer object刚被new 出来,处于idle状态。用户使用OnErrorListener.onError()注册的callback函数不会被内在palyer Engine调用,且状态不会发生改变,继续为idle.
如果是reset() 后处于idle状态,则注册的callback函数被调用。且MediaPlayer object会转为Error状态。
1.2:End状态:
当MediaPlayer object调用release() 后,它处于End 状态。
如果MediaPlayer object不再使用时,请立即调用release(),这样,内部player engine可以释放掉他们所占用的资源。 这类资源,不光包括内存资源,还包括Audio,Video硬件解码设备。
当用户进入End状态后,没有任何渠道去转回其它状态。
1.3:Initialized状态:
当MediaPlayer Object为Idle状态时,调用setDataSource(FileDescriptor), or setDataSource(String), or setDataSource(Context, Uri), or setDataSource(FileDescriptor, long, long)转变其状态到Initialized状态。
如果setDataSource()在非Idle状态调用,
所以,setDataSource()时必须捕获IllegalArgumentException
1.4:Prepared状态:
MediaPlayer Object 必须首先进入Prepared状态,之后才能开始start.
有两种方式进入Prepared状态:
调用prepare() 则以同步方式进入Prepared状态。当prepare()返回时,MediaPlayer Object 已经进入Prepared状态。
调用prepareAsync()则以异步方式进入Prepared状态。
当在错误状态调用prepare() or prepareAsync() ,则抛出异常IllegalStateException。
1.5: Started状态:
要播放,则需要调用start(),当start()返回successfully时,MediaPlayer Object则进入Started状态。
isPlaying()可以测试是否位于Started 状态。
在MediaPlayer Object处于Started状态时,调用start()没有任何效果。
1.6:Paused状态:
调用pause(),当其返回时,MediaoPlayer Object进入Paused状态。从started状态到pasued状态,Play Engine有缺陷。所以导致isPlaying()...
MediaPlayer进入Paused状态后,调用start()重新开始播放(Resume).但Position是从刚才暂停处开始播放,而不是从头。且状态变化为Started。
在Paused状态,再次调用pause()没有反应 。
1.7 Stop状态:
在Started,Paused,Prepared或者PlaybackCompleted状态,调用stop(),则进入Stopped状态。
在Stopped状态,MediaPlayer Object不能再次调用start()去播放,除非调用prepare()或prepareAsync()使其进入Prepared状态。
在Stopped状态下再次调用stop.无效。
1.8
当Video/Audio播放完毕后,进入PlaybackCompleted模式。
但如果使用setLooping(true),则播放完毕后,立刻重新播放。且状态继续为started.
如果setLooping(false).播放完毕后,MediaPlayer Object进入PlaybackCompleted模式,并调用setOnCompletionListener(OnCompletionListener)注册的callback函数。
如在
2. 回调机制:
MediaPlayer使用一些方法来设置回调函数,当发生某种特定情况时,内部palyer Engine会调用之。
使用方法,可以在稍后的例子中看到。
3. 播放指针:
可以调用
下表列出了各种方法在哪些状态下调用合法,在哪些状态下非法以及导致的后果:
Valid and invalid states
Method Name
release()
, the object is no longer available.
reset()
, the object is like being just created.
例子程序如下:
package com.Android.AudioPlayer;
import android.media.MediaPlayer;
import android.util.Log;
import java.io.IOException;
import java.lang.String;
public class MusicPlayer {
static public int Object_Num = 0;
static String TAG = "MusicPlayer";
static MediaPlayer mMP;
static int seekend = 0;
//0: idle. 1: Initialized 2: Prepared 3: Started 4:Paused 5:Stoped 6:PlaybackComplete
static int mode = -1; // -1: End
private static class BufferUpdateListener implements MediaPlayer.OnBufferingUpdateListener
{
public void onBufferingUpdate(MediaPlayer mp, int percent)
{
Log.w(TAG, "updateBuffer.");
return;
}
}
private static class CompletionListener implements MediaPlayer.OnCompletionListener
{
public void onCompletion(MediaPlayer mp)
{
Log.w(TAG, "Mediaplay completion");
return ;
}
}
private static class ErrorListener implements MediaPlayer.OnErrorListener
{
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.w(TAG, "Mediaplay Error");
return false;
}
}
private static class InfoListener implements MediaPlayer.OnInfoListener
{
public boolean onInfo(MediaPlayer mp, int what, int extra)
{
Log.w(TAG, String.format("MediaPlayer Info:[%d]", what));
return false;
}
}
private static class PreparedListener implements MediaPlayer.OnPreparedListener
{
public void onPrepared(MediaPlayer mp)
{
Log.w(TAG, "Mediaplay onPrepared");
return;
}
}
private static class SeekCompleteListener implements MediaPlayer.OnSeekCompleteListener
{
public void onSeekComplete(MediaPlayer mp)
{
Log.w(TAG, "Mediaplay SeekComplete");
seekend = 1;
return;
}
}
public void LoadMusic(String MusicFile)
{
if(Object_Num > 0)
{
unLoadMusic();
}
MediaPlayer mp = new MediaPlayer();
mode = 0; //idle
// set
mp.setOnBufferingUpdateListener(new BufferUpdateListener());
mp.setOnCompletionListener(new CompletionListener());
mp.setOnErrorListener(new ErrorListener());
mp.setOnPreparedListener(new PreparedListener());
mp.setOnSeekCompleteListener(new SeekCompleteListener());
mp.setOnInfoListener(new InfoListener());
//int id = mp.getAudioSessionId();
int position = mp.getCurrentPosition();
Log.w(TAG, String.format("Create MediaPlayer. Position :[%d]", position));
mMP = mp;
try {
mp.setDataSource(MusicFile);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
Log.w(TAG, "setDataSource:IllegalArgumentException");
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
Log.w(TAG, "setDataSource:IllegalStateException");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.w(TAG, "setDataSource:IOException");
e.printStackTrace();
}
mode = 1; //Initialized
try {
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
Log.w(TAG, "prepare:IllegalStateException");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.w(TAG, "prepare:IOException");
e.printStackTrace();
}
mode = 2; //prepared
Object_Num++;
return;
}
public void unLoadMusic()
{
if(Object_Num == 1)
{
mMP.stop();
mMP.release();
mode = -1; //end
Object_Num--;
}
return;
}
public void PlayMusic(boolean looping)
{
if(Object_Num == 1)
{
//Prepared Started Paused PlaybackComplete
if(mode == 2 || mode == 4 || mode == 6 || mode == 3)
{
mMP.seekTo(0);
mMP.setLooping(looping);
mMP.start();
mode = 3;
}
}
return;
}
public void StopMusic()
{
if(Object_Num == 1)
{
// started or paused
if(mode == 3 || mode == 4)
{
mMP.pause();
mMP.seekTo(0);
mode = 4;
}
}
return;
}
public void PauseMusic()
{
if(Object_Num == 1)
{
if(mode == 3 || mode == 4)
mMP.pause();
}
return;
}
public void ResumeMusic()
{
if(Object_Num == 1)
{
if(mode == 4)
mMP.start();
}
return;
}
}
MediaPlayer所支持格式:
这个问题,看到网上有不少人回答。但个人觉得回答并不正确。
MediaPlayer底层具体实现决定了所支持格式。毕竟JAVA层不太可能直接操作硬件去播放Video/Audio. 它也是通过JNI与底层C打交道播放Audio/Video. 那么底层的实现才是决定MediaPlayer支持格式的关键。
例如:Sam使用Hi3716C来测试,发现其底层是用HiPlayer来实现,支持WAV,OGG等。
但MTK5502平台,则只支持WAV.(可能OGG没来的及加入)
0 0
- Android 下音频播放<一> MediaPlayer
- Android学习一、MediaPlayer播放音频
- Android学习一、MediaPlayer播放音频
- Android学习一、MediaPlayer播放音频
- Android MediaPlayer播放音频
- android 音频播放--MediaPlayer
- Android:MediaPlayer播放音频
- android MediaPlayer音频播放
- android MediaPlayer音频播放demo
- android MediaPlayer音频播放demo
- Android之MediaPlayer 音频播放
- android MediaPlayer 音频播放器
- android使用MediaPlayer播放音频
- Android MediaPlayer音频播放总结
- Android中播放音频MediaPlayer
- Android 使用MediaPlayer播放音频
- android 多媒体编程(一) MediaPlayer 播放音频
- android之MediaPlayer播放音频或者视频文件
- easyui分页问题
- 矩阵连乘
- vs2008下用MFC读写excel文件
- 利用DAC(Data-tier Application)实现数据库结构迁移
- tomcat Context 不起作用
- Android 下音频播放<一> MediaPlayer
- RobotFramework+Selenium2Library环境安装
- 多线程服务器的常用编程模型
- 虚拟机中实现Ubuntu上网功能
- docker;创建/分享镜像
- leetcode-Longest Valid Parentheses
- android开发,R,java文件丢失如何找回
- 点击按钮复制链接到我的粘贴板【兼容所有浏览器】
- 利用DAC(Data-tier Application)实现数据库结构迁移