Android Audio简述

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

一、MediaPlayer

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

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

二、音乐播放器

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

1)播放控制接口

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

publicinterfaceIPlayer {

// 播放模式

enumPlayMode {

ONCE, CYCLE

}

// 播放状态

enumStatus {

PLAYING, STOPPED, PAUSING

};

// 获得当前播放模式

PlayMode getMode();

// 设置当前播放模式

voidsetMode(PlayMode mode);

// 获得当前播放状态

Status getStatus();

// 指向上一首音乐

File prev();

// 指向下一首音乐

File next();

// 播放当前音乐

booleanplay();

// 暂停当前音乐

booleanpause();

// 恢复播放音乐

booleanresume();

// 停止当前音乐

booleanstop();

// 释放资源

voidrelease();

}

2)文件列表控件

自定义的ListView控件,主要实现功能如下:

1. 异步搜索/mnt/sdcard/music/目录下所有mp3文件

2. 以自定义适配器方式,使得选中的Item保持高亮背景色

3)文件列表播放器

用MediaPlayer实现了IPlayer播放控制接口。

publicclassFileListViewPlayerimplementsIPlayer,

AdapterView.OnItemClickListener {

privateMediaPlayer mMediaPlayer;// MediaPlayer对象

privateFileListView mFileListView;// FileListView组件

privateArrayList musicFileList;// 音乐文件列表

privateintindex =0;// 当前索引

privatePlayMode mPlayMode = PlayMode.CYCLE;// 播放模式

privateStatus mStatus = Status.STOPPED;// 播放状态

privateOnMusicClickListener listener;// 音乐文件点击监听

// 音乐点击事件监听接口

publicinterfaceOnMusicClickListener {

// 返回true及时播放,false则不及时播放

booleanonMusicClick(File musicFile);

}

publicFileListViewPlayer(FileListView fileListView) {

this.mFileListView = fileListView;

fileListView.setOnItemClickListener(this);// 设置Item点击时间监听

mMediaPlayer = newMediaPlayer();// 创建MediaPlayer对象

}

// 是否有音乐

privatebooleanhasMusic() {

musicFileList = mFileListView.getMusicFileList();

return(null!= musicFileList && musicFileList.size() >=1);

}

// 选中某项&设置索引

privatevoidsetSelection(intposition) {

mFileListView.setSelectItem(position); // 选中position

index = position; // 指向position

}

@Override

publicPlayMode getMode() {

returnmPlayMode;

}

@Override

publicvoidsetMode(PlayMode mode) {

this.mPlayMode = mode;

}

@Override

publicStatus getStatus() {

returnmStatus;

}

@Override

publicFile prev() {

if(hasMusic()) {

intlocation = index -1>=0? index -1

: musicFileList.size() - 1;

setSelection(location);

returnmusicFileList.get(location);

}

returnnull;

}

@Override

publicFile next() {

if(hasMusic()) {

intlocation = index +1

setSelection(location);

returnmusicFileList.get(location);

}

returnnull;

}

@Override

publicbooleanplay() {

if(mStatus != Status.STOPPED || !hasMusic()) {

returnfalse;

}

try{

mMediaPlayer.reset();

mMediaPlayer.setDataSource(musicFileList.get(index).toString());

mMediaPlayer.prepare();

mMediaPlayer.start();

// 如果是顺序循环播放

if(mPlayMode == PlayMode.CYCLE) {

mMediaPlayer

.setOnCompletionListener(newOnCompletionListener() {

@Override

publicvoidonCompletion(MediaPlayer mp) {

stop(); // 停止

next(); // 下首

play(); // 播放

}

});

}

mStatus = Status.PLAYING;

returntrue;

} catch(Exception e) {

e.printStackTrace();

}

returnfalse;

}

@Override

publicbooleanpause() {

if(mStatus != Status.PLAYING) {

returnfalse;

}

mMediaPlayer.pause();

mStatus = Status.PAUSING;

returntrue;

}

@Override

publicbooleanresume() {

if(mStatus != Status.PAUSING) {

returnfalse;

}

mMediaPlayer.start();

mStatus = Status.PLAYING;

returntrue;

}

@Override

publicbooleanstop() {

if(mStatus != Status.STOPPED) {

mMediaPlayer.stop();

mStatus = Status.STOPPED;

returntrue;

}

returnfalse;

}

@Override

publicvoidrelease() {

stop();

mMediaPlayer.release();

mMediaPlayer = null;

}

@Override

publicvoidonItemClick(AdapterView> parent, View view,intposition,

longid) {

setSelection(position);

if(null!= listener && hasMusic()) {

if(listener.onMusicClick(musicFileList.get(position))) {

stop(); // 停止

play(); // 播放

}

}

}

publicvoidsetOnMusicClickListener(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基本的播放控制方法。方法的详细说明都在注释了^^。

publicclassSoundPoolActivityextendsActivityimplements

SoundPool.OnLoadCompleteListener {

privatestaticfinalintSOUND_BASE =0;

privatestaticfinalintSOUND_THUNDER = SOUND_BASE +1;

privatestaticfinalintSOUND_NIGHTINGALE = SOUND_BASE +2;

privateSoundPool mSoundPool;// SoundPool对象

privateHashMap soundPoolMap;

@Override

protectedvoidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.audio_pool);

initSounds(); // 初始化SoundPool

}

// 初始化SoundPool

privatevoidinitSounds() {

/*

* SoundPool(int maxStreams, int streamType, int srcQuality)

*

* maxStreams:同时播放的流的最大数量

* streamType:流的类型(AudioManager类中描述的)。例如:游戏应用一般使用STREAM_MUSIC

* srcQuality:采样率转化质量。当前无效果,使用0作为默认值

*/

mSoundPool = newSoundPool(4, AudioManager.STREAM_MUSIC,100);

/*

* Android 2.2(API 8及以上)才有这接口==

*/

mSoundPool.setOnLoadCompleteListener(this);

soundPoolMap = newHashMap();

/*

* 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));

}

// 雷声

publicvoidbird(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);

}

// 雷声+夜莺

publicvoidmix(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

publicvoidonBackPressed() {

super.onBackPressed();

mSoundPool.release();

}

@Override

publicvoidonLoadComplete(SoundPool soundPool,intsampleId,intstatus) {

// Log.d("TAG", "==" + sampleId + "==");

}

}

四、MediaRecorder

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

五、简易录音机

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

1)录音机对象

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

publicclassRecorderimplementsOnCompletionListener, OnErrorListener {

// 录音机状态

publicenumStatus {

IDLE, RECORDING, PLAYING

}

// 当前状态

privateStatus mStatus = Status.IDLE;

// 媒体录制对象

privateMediaRecorder mRecorder =null;

// 媒体播放对象

privateMediaPlayer mPlayer =null;

// 录制的文件

File mSampleFile = null;

// 录音或播放开始时间

longmSampleStart =0;

privateOnRecorderListener listener;// 播放器接口

publicinterfaceOnRecorderListener {

voiderror();

voidplayOver();

}

// 返回录音机状态

publicStatus getStatus() {

returnmStatus;

}

// 是否录过音

publicbooleanisRecorded() {

returnmSampleFile !=null;

}

// 返回时间进度(秒)

publicintprogress() {

if(mStatus == Status.RECORDING || mStatus == Status.PLAYING)

return(int) ((System.currentTimeMillis() - mSampleStart) /1000);

return0;

}

// 开始录音

publicvoidstartRecording() {

stop(); // 停止

if(mSampleFile ==null) {

// 创建文件,以createTempFile方式避免覆盖

try{

File dir = newFile(Environment.getExternalStorageDirectory()

+ "/AndroidMedia/");

if(!dir.exists()) {

dir.mkdirs();

}

mSampleFile = File.createTempFile("join_",".3gpp", dir);

} catch(IOException e) {

e.printStackTrace();

return;

}

}

mRecorder = newMediaRecorder();// 创建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; // 设置录音状态

}

// 停止录音

publicvoidstopRecording() {

if(mRecorder ==null)

return;

mRecorder.stop(); // 停止录音

mRecorder.release(); // 释放资源

mRecorder = null;// 重置为null

mStatus = Status.IDLE; // 设为空闲状态

}

// 开始录音

publicvoidstartPlayback() {

stop(); // 停止

mPlayer = newMediaPlayer();// 创建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; // 设置录音状态

}

// 停止录音

publicvoidstopPlayback() {

if(mPlayer ==null)

return;

mPlayer.stop(); // 停止播放

mPlayer.release(); // 释放资源

mPlayer = null;// 重置为null

mStatus = Status.IDLE; // 设为空闲状态

}

// 停止操作

publicvoidstop() {

stopRecording();

stopPlayback();

}

@Override

publicbooleanonError(MediaPlayer mp,intwhat,intextra) {

stop(); // 停止

if(null!= listener) {

listener.error();

}

returntrue;

}

@Override

publicvoidonCompletion(MediaPlayer mp) {

stop(); // 停止

if(null!= listener) {

listener.playOver();

}

}

// 设置播放器接口

publicvoidsetOnRecorderListener(OnRecorderListener listener) {

this.listener = listener;

}

}

2)录音机活动

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

3)其他设置(样例中未写)

MediaRecorder的getMaxAmplitude()可以获得音频资源的最大振幅,可以用于展示下录音时的波幅线条?

增加设置文件大小限制或物体空间限制,提示剩余时间。物理空间可以用package android.os包内的StatFs类。StatFs是Unix statfs()的一个包装,用于检索文件系统空间的整体信息。在之前Camera摄像的CameraVideoActivity内稍带用了下的^^。

当然,这些功能在系统自带的录音机里都有实现了的,直接可以用==。

六、后记

1)扩展内容

1.1)android获取多媒体信息之音频文件

1.2)RandomMusicPlayer:Service方式如何进行音乐播放控制(官方例子)

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

2)模块概览

2.1)Audio MediaPlayer

2.2)Audio SoundPool

2.3)Audio MeidaRecorder

3)运行效果

3.1)音乐播放器

3.2)SoundPool

3.3)简单录音机

android getduration 毫秒,,Android Audio简述相关推荐

  1. android getduration 毫秒,,VideoView中getDuration()和getCurrentPosition()獲取錯誤的問題

    這幾天在做一個App內嵌VideoView的工作. 要實現正在播放的時候,按home鍵到桌面后,再進入該App,視頻還在剛才的進度上播放. 實現思路是再onStop()中調用videoView.get ...

  2. android获取毫秒,Android 日期转为为毫秒,毫秒转化为日期,获取当期日期年、月、日...

    //将时间毫秒值转化为年月日 val date = Date(System.currentTimeMillis()) val simpleDateFormat = SimpleDateFormat(& ...

  3. android 时间 毫秒,android 有关毫秒转时间的方法,及时间间隔等

    /** * Created by baiyuanwei on 16/5/3. * * "HH:mm:ss"是24小时制的,"hh:mm:ss"是12小时制. * ...

  4. [转]Android Audio简述

    转自:http://vaero.blog.51cto.com/4350852/834880 Android Audio简述 简单点MediaPlayer,复杂点--不会啊T^T,怎么办! 一.Medi ...

  5. android 指纹识别支付 secure os,Android指纹登录/指纹支付简述

    一.简述 业务需求,需要指纹登录,鉴于市面上的资料不是特别齐全,走了不少弯路.现在通了,写点东西给大伙做个参考.末尾会提供demo和参考资料 二.指纹登录/支付工作流程 指纹验证加密流程.png 最新 ...

  6. Android底层开发之Audio HAL Android Audio Overview

    http://blog.csdn.net/kangear/article/details/44939429 Android底层开发之Audio HAL 在Android音频底层调试-基于tinyals ...

  7. Android 注解与注解处理器简述

    Android 注解与注解处理器简述 前言 正文 一.注解 ① 注解类型 ② 注解生命周期 ③ 注解参数 二.注解处理器 ① 注册 ② 配置 三.使用 ① 接口 ② 反射 ③ 使用 ④ 强化 四.源码 ...

  8. android显示二维毫秒,Android应用开发Android 悬浮窗显示毫秒级时间

    本文将带你了解Android应用开发Android 悬浮窗显示毫秒级时间,希望本文对大家学Android有所帮助. Android   悬浮窗显示毫秒级时间Android 悬浮窗显示毫秒级时间. 运行 ...

  9. Android底层开发之Audio HAL

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Andr ...

最新文章

  1. python打开文件_喜大普奔 | 如何在Win10下利用Python打开grib文件
  2. Jenkins命令可视化
  3. MYSQL:基础——触发器
  4. 一个div 上下两行_Django 实战 | 搭一个 GitHub 用户展示网站 02
  5. javascript中的Base64.UTF8编码与解码详解
  6. 大数据与商业地理分析
  7. 【备忘】尚硅谷Scala视频
  8. 单元三:阻抗匹配(电容电感,变压器,传输线变压器,附带硬件电路)
  9. html5制作叮当猫,HTML5 canvas画简单的叮当猫头
  10. 【计算几何】求三角形外接圆的周长、面积公式
  11. 数据库实验7---数据库的备份与恢复
  12. 寻找最小生成树的欧拉路径,即一笔画问题
  13. 全文检索Elasticsearch研究
  14. C++ cout输出中文
  15. 华为认证HCIP难考吗?
  16. Spring源码解析十五
  17. 菜单侧边栏拖拽_SwiftUI —侧边栏菜单教程
  18. 大数据、云计算、物联网、数据库、数据仓库、OLAP、OLTP等学习大数据你必须了解的概念,我的学习总结
  19. php数组去重的函数,php数组去重函数的简单示例
  20. 淘宝服饰精品案例分析

热门文章

  1. 有符号数与无符号数的加减法
  2. 语义分割与实例分割 Labelme标注教学
  3. potato土豆登录不了_皮到爆炸的搞笑句子朋友圈 现在的心情就是去了皮的大土豆...
  4. 1984年计算机屏幕有多大,19.5英寸的计算机显示屏有多大?
  5. 腾讯云校园云服务器—活动地址
  6. 0x3f3f3f3f知多少
  7. DSM、DEM、H互相计算
  8. 自学大数据第四天~hadoop集群的搭建(一)
  9. Dynamo-Amazon高可用键值存储 笔记
  10. PFlash和DFlash的区别