转自:http://vaero.blog.51cto.com/4350852/834880

Android Audio简述
简单点MediaPlayer,复杂点……不会啊T^T,怎么办!

一、MediaPlayer

在package android.media包内,MediaPlayer的API说明得很详细了^^。摘张图过来:

另外,在其Valid and invalid states一节中列了张表格,详细的描述了MediaPlayer各方法在各状态下是否有效。(就不摘过来了^^)

二、音乐播放器
MediaPlayer控制音乐文件播放的简易实现,就是控制上图的流程^^。

1)播放控制接口
定义了播放器基本模式、状态及控制操作方法。


    public interface IPlayer {              // 播放模式         enum PlayMode {             ONCE, CYCLE         }              // 播放状态         enum Status {             PLAYING, STOPPED, PAUSING         };              // 获得当前播放模式         PlayMode getMode();              // 设置当前播放模式         void setMode(PlayMode mode);              // 获得当前播放状态         Status getStatus();              // 指向上一首音乐         File prev();              // 指向下一首音乐         File next();              // 播放当前音乐         boolean play();              // 暂停当前音乐         boolean pause();              // 恢复播放音乐         boolean resume();              // 停止当前音乐         boolean stop();              // 释放资源         void release();          } 



2)文件列表控件
自定义的ListView控件,主要实现功能如下:
1. 异步搜索/mnt/sdcard/music/目录下所有mp3文件
2. 以自定义适配器方式,使得选中的Item保持高亮背景色

3)文件列表播放器
用MediaPlayer实现了IPlayer播放控制接口。


   public class FileListViewPlayer implements IPlayer,             AdapterView.OnItemClickListener {              private MediaPlayer mMediaPlayer; // MediaPlayer对象         private FileListView mFileListView; // FileListView组件         private ArrayList<File> musicFileList; // 音乐文件列表         private int index = 0; // 当前索引         private PlayMode mPlayMode = PlayMode.CYCLE; // 播放模式         private Status mStatus = Status.STOPPED; // 播放状态              private OnMusicClickListener listener; // 音乐文件点击监听              // 音乐点击事件监听接口         public interface OnMusicClickListener {             // 返回true及时播放,false则不及时播放             boolean onMusicClick(File musicFile);         }              public FileListViewPlayer(FileListView fileListView) {             this.mFileListView = fileListView;             fileListView.setOnItemClickListener(this); // 设置Item点击时间监听             mMediaPlayer = new MediaPlayer(); // 创建MediaPlayer对象         }              // 是否有音乐         private boolean hasMusic() {             musicFileList = mFileListView.getMusicFileList();             return (null != musicFileList && musicFileList.size() >= 1);         }              // 选中某项&设置索引         private void setSelection(int position) {             mFileListView.setSelectItem(position); // 选中position             index = position; // 指向position         }              @Override         public PlayMode getMode() {             return mPlayMode;         }              @Override         public void setMode(PlayMode mode) {             this.mPlayMode = mode;         }              @Override         public Status getStatus() {             return mStatus;         }              @Override         public File prev() {             if (hasMusic()) {                 int location = index - 1 >= 0 ? index - 1                         : musicFileList.size() - 1;                 setSelection(location);                 return musicFileList.get(location);             }             return null;         }              @Override         public File next() {             if (hasMusic()) {                 int location = index + 1 < musicFileList.size() ? index + 1 : 0;                 setSelection(location);                 return musicFileList.get(location);             }             return null;         }              @Override         public boolean play() {             if (mStatus != Status.STOPPED || !hasMusic()) {                 return false;             }             try {                 mMediaPlayer.reset();                 mMediaPlayer.setDataSource(musicFileList.get(index).toString());                 mMediaPlayer.prepare();                 mMediaPlayer.start();                 // 如果是顺序循环播放                 if (mPlayMode == PlayMode.CYCLE) {                     mMediaPlayer                             .setOnCompletionListener(new OnCompletionListener() {                                 @Override                                 public void onCompletion(MediaPlayer mp) {                                     stop(); // 停止                                     next(); // 下首                                     play(); // 播放                                 }                             });                 }                 mStatus = Status.PLAYING;                 return true;             } catch (Exception e) {                 e.printStackTrace();             }             return false;         }              @Override         public boolean pause() {             if (mStatus != Status.PLAYING) {                 return false;             }             mMediaPlayer.pause();             mStatus = Status.PAUSING;             return true;         }              @Override         public boolean resume() {             if (mStatus != Status.PAUSING) {                 return false;             }             mMediaPlayer.start();             mStatus = Status.PLAYING;             return true;         }              @Override         public boolean stop() {             if (mStatus != Status.STOPPED) {                 mMediaPlayer.stop();                 mStatus = Status.STOPPED;                 return true;             }             return false;         }              @Override         public void release() {             stop();             mMediaPlayer.release();             mMediaPlayer = null;         }              @Override         public void onItemClick(AdapterView<?> parent, View view, int position,                 long id) {             setSelection(position);             if (null != listener && hasMusic()) {                 if (listener.onMusicClick(musicFileList.get(position))) {                     stop(); // 停止                     play(); // 播放                 }             }         }              public void setOnMusicClickListener(OnMusicClickListener listener) {             this.listener = listener;         }          } 



4)播放器活动
界面上各点击事件与播放控制接口结合。

5)其他设置(样例中未写==)
5.1)播放进度
使用MediaPlayer提供了如下3个方法即可:

1. getDuration():获得总持续时间(毫秒)
{Idle, Initialized, Error}状态时,该方法无效。

2. getCurrentPosition():获得当前播放位置(毫秒)
{Error}状态时,该方法无效。

3. seekTo(int msec):跳至指定的时间位置(毫秒)

{Idle, Initialized, Stopped, Error}状态时,该方法无效。

5.2)音量控制

使用AudioManager的setStreamVolume(int streamType, int index, int flags)方法。第一个参数设置为AudioManager.STREAM_MUSIC,即为音乐音量。

三、其他音频类

一样是在package android.media包内,还有好几个以Player后缀结束的类呢T^T。没用过,也不多作介绍了。
这节呢,主要是想介绍下SoundPool,以及它与MediaPlayer的利弊及使用场合。

1)利弊及场合
MediaPlayer资源占用多、延迟长、不支持多个音频同时播放。在快速连续播放音效时,尤其会感受到。而SoundPool则不同,占用少、延迟短、支持多音频播放。因为其限制最大只能申请1M的内存,也就意味着是用于播放音频片断的。
总结就是,MediaPlayer播放长音乐,SoundPool播放短音效==。

2)SoundPool注意点
1. 音效文件不易过大(限制1M内存)
如果音效文件过大而没有载入完成,调用play()可能会产生严重的后果。当然可以用SoundPool.OnLoadCompleteListener来判断是否载入完成。
2. pause&stop方法建议不轻易使用
有时会使你程序莫名终止。也有反映不会立即终止,而是等缓冲区播放完,会多一秒。
3. 音频格式建议使用OGG格式。
说是WAV在音效播放间隔较短的情况下会出现异常关闭的情况。另外说是,目前只对16位的WAV支持较好。(目前不知道指什么时候==)

参考自网络,未亲自证实,尽量避免就行了^^。

3)SoundPool的使用
SoundPool基本的播放控制方法。方法的详细说明都在注释了^^。


  public class SoundPoolActivity extends Activity implements             SoundPool.OnLoadCompleteListener {              private static final int SOUND_BASE = 0;         private static final int SOUND_THUNDER = SOUND_BASE + 1;         private static final int SOUND_NIGHTINGALE = SOUND_BASE + 2;              private SoundPool mSoundPool; // SoundPool对象         private HashMap<Integer, Integer> soundPoolMap;              @Override         protected void onCreate(Bundle savedInstanceState) {             super.onCreate(savedInstanceState);             setContentView(R.layout.audio_pool);             initSounds(); // 初始化SoundPool         }              // 初始化SoundPool         private void initSounds() {             /*              * SoundPool(int maxStreams, int streamType, int srcQuality)              *               * maxStreams:同时播放的流的最大数量              * streamType:流的类型(AudioManager类中描述的)。例如:游戏应用一般使用STREAM_MUSIC              * srcQuality:采样率转化质量。当前无效果,使用0作为默认值              */             mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);             /*              * Android 2.2(API 8及以上)才有这接口==              */             mSoundPool.setOnLoadCompleteListener(this);             soundPoolMap = new HashMap<Integer, Integer>();             /*              * load()有四种方法,如下:              *               * 1)int load(Context context, int resId, int priority)              *     从APK资源载入(一般在res/raw目录下)              * 2)int load(FileDescriptor fd, long offset, long length, int priority)              *     从FileDescriptor对象载入              * 3)int load(AssetFileDescriptor afd, int priority)              *     从Asset对象载入              * 4)int load(String path, int priority)              *     从完整文件路径名载入              *               * 最后priority参数为优先级,播放多文件时处理用。              */             soundPoolMap                     .put(SOUND_THUNDER, mSoundPool.load(this, R.raw.thunder, 1));             soundPoolMap.put(SOUND_NIGHTINGALE,                     mSoundPool.load(this, R.raw.nightingale, 2));         }              // 雷声         public void bird(View v) {             /*              * play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)              *               * soundID:load()方法返回的int值              * leftVolume:左音量。范围=[0.0,1.0]              * rightVolume:右音量。范围=[0.0,1.0]              * priority:优先级。最低=0              * loop:循环次数。不循环=0;永远循环=-1              * rate:速率。正常=1;范围=[0.5,2.0]              */             mSoundPool.play(soundPoolMap.get(SOUND_THUNDER), 1, 1, 0, 0, 1);         }              // 雷声+夜莺         public void mix(View v) {             mSoundPool.play(soundPoolMap.get(SOUND_THUNDER), 1, 1, 0, 0, 1);             mSoundPool.play(soundPoolMap.get(SOUND_NIGHTINGALE), 1, 1, 0, 0, 1);         }              @Override         public void onBackPressed() {             super.onBackPressed();             mSoundPool.release();         }              @Override         public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {             // Log.d("TAG", "==" + sampleId + "==");         }          } 



四、MediaRecorder
在Camera摄像里,MediaRecorder用来录制视频了。这里是介绍录制音频了^^。好吧,再摘张图过来(真心觉着看看API就好了,可以把我忽视==):


五、简易录音机
简易的录音机,就是能录音和回放一下的那种==。

1)录音机对象
录音机的简单实现。MediaRecorder控制录音、MediaPlayer用于播放,设置了其各个阶段状态。


  public class Recorder implements OnCompletionListener, OnErrorListener {              // 录音机状态         public enum Status {             IDLE, RECORDING, PLAYING         }              // 当前状态         private Status mStatus = Status.IDLE;              // 媒体录制对象         private MediaRecorder mRecorder = null;         // 媒体播放对象         private MediaPlayer mPlayer = null;         // 录制的文件         File mSampleFile = null;         // 录音或播放开始时间         long mSampleStart = 0;              private OnRecorderListener listener; // 播放器接口              public interface OnRecorderListener {             void error();                  void playOver();         }              // 返回录音机状态         public Status getStatus() {             return mStatus;         }              // 是否录过音         public boolean isRecorded() {             return mSampleFile != null;         }              // 返回时间进度(秒)         public int progress() {             if (mStatus == Status.RECORDING || mStatus == Status.PLAYING)                 return (int) ((System.currentTimeMillis() - mSampleStart) / 1000);             return 0;         }              // 开始录音         public void startRecording() {             stop(); // 停止             if (mSampleFile == null) {                 // 创建文件,以createTempFile方式避免覆盖                 try {                     File dir = new File(Environment.getExternalStorageDirectory()                             + "/AndroidMedia/");                     if (!dir.exists()) {                         dir.mkdirs();                     }                     mSampleFile = File.createTempFile("join_", ".3gpp", dir);                 } catch (IOException e) {                     e.printStackTrace();                     return;                 }             }             mRecorder = new MediaRecorder(); // 创建MediaRecorder对象             mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置音频信号源:麦克风             mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); // 设置输出格式             mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 设置音频编码器             mRecorder.setOutputFile(mSampleFile.getAbsolutePath()); // 设置输出文件             try {                 mRecorder.prepare(); // 准备录音             } catch (Exception e) {                 mRecorder.reset(); // 重置空闲                 mRecorder.release(); // 释放资源                 mRecorder = null; // 重置为null                 return; // 返回             }             try {                 mRecorder.start(); // 开启录音             } catch (RuntimeException e) {                 // 可能开启不了,如果是来电的话,可以如下判断:                 // AudioManager.getMode() == MODE_IN_CALL || MODE_IN_COMMUNICATION                 mRecorder.reset(); // 重置空闲                 mRecorder.release(); // 释放资源                 mRecorder = null; // 重置为null                 return; // 返回             }             mSampleStart = System.currentTimeMillis(); // 初始化开始时间             mStatus = Status.RECORDING; // 设置录音状态         }              // 停止录音         public void stopRecording() {             if (mRecorder == null)                 return;             mRecorder.stop(); // 停止录音             mRecorder.release(); // 释放资源             mRecorder = null; // 重置为null             mStatus = Status.IDLE; // 设为空闲状态         }              // 开始录音         public void startPlayback() {             stop(); // 停止             mPlayer = new MediaPlayer(); // 创建MediaPlayer对象             try {                 mPlayer.setDataSource(mSampleFile.getAbsolutePath()); // 设置数据资源路径                 mPlayer.setOnCompletionListener(this); // 设置完成监听接口                 mPlayer.setOnErrorListener(this); // 设置错误监听接口                 mPlayer.prepare(); // 准备                 mPlayer.start(); // 播放             } catch (Exception e) {                 mPlayer = null; // 重置为null                 return;             }             mSampleStart = System.currentTimeMillis(); // 初始化开始时间             mStatus = Status.PLAYING; // 设置录音状态         }              // 停止录音         public void stopPlayback() {             if (mPlayer == null)                 return;             mPlayer.stop(); // 停止播放             mPlayer.release(); // 释放资源             mPlayer = null; // 重置为null             mStatus = Status.IDLE; // 设为空闲状态         }              // 停止操作          public void stop() {             stopRecording();             stopPlayback();         }              @Override         public boolean onError(MediaPlayer mp, int what, int extra) {             stop(); // 停止             if (null != listener) {                 listener.error();             }             return true;         }              @Override         public void onCompletion(MediaPlayer mp) {             stop(); // 停止             if (null != listener) {                 listener.playOver();             }         }              // 设置播放器接口         public void setOnRecorderListener(OnRecorderListener listener) {             this.listener = listener;         }          } 



2)录音机活动
录音机控制界面。进行录音&播放控制,并显示有时间。

3)其他设置(样例中未写)
MediaRecorder的getMaxAmplitude()可以获得音频资源的最大振幅,可以用于展示下录音时的波幅线条?
增加设置文件大小限制或物体空间限制,提示剩余时间。物理空间可以用package android.os包内的StatFs类。StatFs是Unix statfs()的一个包装,用于检索文件系统空间的整体信息。在之前Camera摄像的CameraVideoActivity内稍带用了下的^^。
当然,这些功能在系统自带的录音机里都有实现了的,直接可以用==。

六、后记
1)扩展内容
1.1)android获取多媒体信息之音频文件
http://hi.baidu.com/shiwl111/blog/item/98b42ed041ea7c2d960a16d8.html

1.2)RandomMusicPlayer:Service方式如何进行音乐播放控制(官方例子)
http://developer.android.com/resources/samples/RandomMusicPlayer/index.html

1.3)Jamendo:一款开源在线音乐播放器

Google Code:http://code.google.com/p/jamendo/
源码分析系列:http://blog.csdn.net/gaomatrix/article/category/900092

2)模块概览
2.1)Audio MediaPlayer


2.2)Audio SoundPool


2.3)Audio MeidaRecorder

Audio MeidaRecorder

3)运行效果
3.1)音乐播放器

Audio MeidaRecorder

3.2)SoundPool

Audio MeidaRecorder

3.3)简单录音机

Audio MeidaRecorder



本文出自 “-_--___---_-” 博客,请务必保留此出处http://vaero.blog.51cto.com/4350852/834880

更多相关文章

  1. 实现简单的Android的播放视频功能
  2. android 动态设置Activity 的切换方向
  3. android之实现底部TabHost
  4. Android之进度条
  5. Android小知识积累
  6. Android(安卓)软键盘问题总结
  7. android 播放视频
  8. ExpandableListView设置选中child的背景
  9. Android中的AnimationDrawable的使用

随机推荐

  1. android iphone ui 设计 相关网站
  2. Android下修改SeekBar样式
  3. Android(安卓)程序打包及签名
  4. Android单元测试学习记录
  5. Android实用代码
  6. Android屏蔽返回键
  7. Android休眠唤醒驱动流程分析
  8. Android(安卓)Studio提升编译速度
  9. d
  10. Android拍照、录像、录音代码范例