Android(安卓)Audio简述
16lz
2021-01-26
Android Audio 简述 简单点MediaPlayer,复杂点……不会啊T^T,怎么办! 一、 MediaPlayer
在package android.media包内,MediaPlayer的API说明得很详细了^^。摘张图过来:
另外,在其Valid and invalid states一节中列了张表格,详细的描述了MediaPlayer各方法在各状态下是否有效。(就不摘过来了^^) 二、音乐播放器 MediaPlayer控制音乐文件播放的简易实现,就是控制上图的流程^^。 1 )播放控制接口 定义了播放器基本模式、状态及控制操作方法。2 )文件列表控件 自定义的ListView控件,主要实现功能如下: 1. 异步搜索/ mnt/ sdcard/music/目录下所有mp3文件 2. 以自定义适配器方式,使得选中的Item保持高亮背景色 3 )文件列表播放器 用MediaPlayer实现了IPlayer播放控制接口。
- publicinterfaceIPlayer{
- //播放模式
- enumPlayMode{
- ONCE,CYCLE
- }
- //播放状态
- enumStatus{
- PLAYING,STOPPED,PAUSING
- };
- //获得当前播放模式
- PlayModegetMode();
- //设置当前播放模式
- voidsetMode(PlayModemode);
- //获得当前播放状态
- StatusgetStatus();
- //指向上一首音乐
- Fileprev();
- //指向下一首音乐
- Filenext();
- //播放当前音乐
- booleanplay();
- //暂停当前音乐
- booleanpause();
- //恢复播放音乐
- booleanresume();
- //停止当前音乐
- booleanstop();
- //释放资源
- voidrelease();
- }
4 )播放器活动 界面上各点击事件与播放控制接口结合。 5 )其他设置(样例中未写== ) 5.1)播放进度 使用MediaPlayer提供了如下3个方法即可:
- publicclassFileListViewPlayerimplementsIPlayer,
- AdapterView.OnItemClickListener{
- privateMediaPlayermMediaPlayer;//MediaPlayer对象
- privateFileListViewmFileListView;//FileListView组件
- privateArrayList<File>musicFileList;//音乐文件列表
- privateintindex=0;//当前索引
- privatePlayModemPlayMode=PlayMode.CYCLE;//播放模式
- privateStatusmStatus=Status.STOPPED;//播放状态
- privateOnMusicClickListenerlistener;//音乐文件点击监听
- //音乐点击事件监听接口
- publicinterfaceOnMusicClickListener{
- //返回true及时播放,false则不及时播放
- booleanonMusicClick(FilemusicFile);
- }
- publicFileListViewPlayer(FileListViewfileListView){
- 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
- publicPlayModegetMode(){
- returnmPlayMode;
- }
- @Override
- publicvoidsetMode(PlayModemode){
- this.mPlayMode=mode;
- }
- @Override
- publicStatusgetStatus(){
- returnmStatus;
- }
- @Override
- publicFileprev(){
- if(hasMusic()){
- intlocation=index-1>=0?index-1
- :musicFileList.size()-1;
- setSelection(location);
- returnmusicFileList.get(location);
- }
- returnnull;
- }
- @Override
- publicFilenext(){
- if(hasMusic()){
- intlocation=index+1<musicFileList.size()?index+1:0;
- 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(MediaPlayermp){
- stop();//停止
- next();//下首
- play();//播放
- }
- });
- }
- mStatus=Status.PLAYING;
- returntrue;
- }catch(Exceptione){
- 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,Viewview,intposition,
- longid){
- setSelection(position);
- if(null!=listener&&hasMusic()){
- if(listener.onMusicClick(musicFileList.get(position))){
- stop();//停止
- play();//播放
- }
- }
- }
- publicvoidsetOnMusicClickListener(OnMusicClickListenerlistener){
- this.listener=listener;
- }
- }
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基本的播放控制方法。方法的详细说明都在注释了^^。四、 MediaRecorder 在Camera摄像里,MediaRecorder用来录制视频了。这里是介绍录制音频了^^。好吧,再摘张图过来(真心觉着看看API就好了,可以把我忽视==): 五、简易录音机 简易的录音机,就是能录音和回放一下的那种==。 1 )录音机对象 录音机的简单实现。MediaRecorder控制录音、MediaPlayer用于播放,设置了其各个阶段状态。
- publicclassSoundPoolActivityextendsActivityimplements
- SoundPool.OnLoadCompleteListener{
- privatestaticfinalintSOUND_BASE=0;
- privatestaticfinalintSOUND_THUNDER=SOUND_BASE+1;
- privatestaticfinalintSOUND_NIGHTINGALE=SOUND_BASE+2;
- privateSoundPoolmSoundPool;//SoundPool对象
- privateHashMap<Integer,Integer>soundPoolMap;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.audio_pool);
- initSounds();//初始化SoundPool
- }
- //初始化SoundPool
- privatevoidinitSounds(){
- /*
- *SoundPool(intmaxStreams,intstreamType,intsrcQuality)
- *
- *maxStreams:同时播放的流的最大数量
- *streamType:流的类型(AudioManager类中描述的)。例如:游戏应用一般使用STREAM_MUSIC
- *srcQuality:采样率转化质量。当前无效果,使用0作为默认值
- */
- mSoundPool=newSoundPool(4,AudioManager.STREAM_MUSIC,100);
- /*
- *Android2.2(API8及以上)才有这接口==
- */
- mSoundPool.setOnLoadCompleteListener(this);
- soundPoolMap=newHashMap<Integer,Integer>();
- /*
- *load()有四种方法,如下:
- *
- *1)intload(Contextcontext,intresId,intpriority)
- *从APK资源载入(一般在res/raw目录下)
- *2)intload(FileDescriptorfd,longoffset,longlength,intpriority)
- *从FileDescriptor对象载入
- *3)intload(AssetFileDescriptorafd,intpriority)
- *从Asset对象载入
- *4)intload(Stringpath,intpriority)
- *从完整文件路径名载入
- *
- *最后priority参数为优先级,播放多文件时处理用。
- */
- soundPoolMap
- .put(SOUND_THUNDER,mSoundPool.load(this,R.raw.thunder,1));
- soundPoolMap.put(SOUND_NIGHTINGALE,
- mSoundPool.load(this,R.raw.nightingale,2));
- }
- //雷声
- publicvoidbird(Viewv){
- /*
- *play(intsoundID,floatleftVolume,floatrightVolume,intpriority,intloop,floatrate)
- *
- *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(Viewv){
- 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(SoundPoolsoundPool,intsampleId,intstatus){
- //Log.d("TAG","=="+sampleId+"==");
- }
- }
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:一款开源在线音乐播放器
- publicclassRecorderimplementsOnCompletionListener,OnErrorListener{
- //录音机状态
- publicenumStatus{
- IDLE,RECORDING,PLAYING
- }
- //当前状态
- privateStatusmStatus=Status.IDLE;
- //媒体录制对象
- privateMediaRecordermRecorder=null;
- //媒体播放对象
- privateMediaPlayermPlayer=null;
- //录制的文件
- FilemSampleFile=null;
- //录音或播放开始时间
- longmSampleStart=0;
- privateOnRecorderListenerlistener;//播放器接口
- publicinterfaceOnRecorderListener{
- voiderror();
- voidplayOver();
- }
- //返回录音机状态
- publicStatusgetStatus(){
- 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{
- Filedir=newFile(Environment.getExternalStorageDirectory()
- +"/AndroidMedia/");
- if(!dir.exists()){
- dir.mkdirs();
- }
- mSampleFile=File.createTempFile("join_",".3gpp",dir);
- }catch(IOExceptione){
- 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(Exceptione){
- mRecorder.reset();//重置空闲
- mRecorder.release();//释放资源
- mRecorder=null;//重置为null
- return;//返回
- }
- try{
- mRecorder.start();//开启录音
- }catch(RuntimeExceptione){
- //可能开启不了,如果是来电的话,可以如下判断:
- //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(Exceptione){
- 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(MediaPlayermp,intwhat,intextra){
- stop();//停止
- if(null!=listener){
- listener.error();
- }
- returntrue;
- }
- @Override
- publicvoidonCompletion(MediaPlayermp){
- stop();//停止
- if(null!=listener){
- listener.playOver();
- }
- }
- //设置播放器接口
- publicvoidsetOnRecorderListener(OnRecorderListenerlistener){
- this.listener=listener;
- }
- }
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 3 )运行效果 3.1)音乐播放器 3.2)SoundPool 3.3)简单录音机更多相关文章
- android自定义view控件
- 自定义Dialog宽度设定
- android状态栏一体化(改变状态栏的背景颜色)
- Android(安卓)FrameLayout布局中的控件设置居中动态设置
- 关于Android主题splash全屏和主页面的沉浸式状态栏
- TextInputEditText样式设置
- Android(安卓)使用Visualizer获取播放音频的频率
- Android之EditText 属性汇总 +限定输入某些特殊字符
- Android(安卓)6.0新控件属性记录