Android 音頻播放——AudioTrack直接播PCM、MediaPlayer播媒體文件能夠是audio

http://blog.csdn.net/java_android_c/article/details/52678265html

 

Android平臺播放音頻的方式通常有3種。1.利用系統內置的應用程序播放音頻    2.利用AudioTrack播放原始音頻   3.使用MediaPlayer播放。此3種音頻播放方式,以第三種MediaPlayer播放這種方式使用的最多,必須掌握!java

1、使用系統內置的程序。android

Google想的「周到」,通常都給咱們提供了一些內置程序,然而這些內置程序的UI效果,那真是感人啊!通常內置程序,咱們就是看看而已。數組

 

[java]  view plain  copy
 
  1. Intent intent=new Intent(Intent.ACTION_VIEW);  
  2. intent.setDataAndType(url,type); //eg:intent.setDataAndType(url,「audio/mp3」);  url音頻文件路徑  
  3. startActivity(intent);  


2、使用AudioTrack播放音頻:只能播放原始的PCM數據,經過callback函數一直寫入HW。實際上MediaPlayer也是經過AudioTrack來播放音頻的緩存

 在NuPlayer有一個mAudioSink,實際是AudioOutput類型,內部有一個AudioTrack,用來播放解碼後的PCM數據網絡

AudioTrack只能用來播放原始音頻(PCM)異步

[java]  view plain  copy
 
  1. //播放音頻(PCM)  
  2.     public void play()  
  3.     {     
  4.         DataInputStream dis=null;  
  5.         try {  
  6.              //從音頻文件中讀取聲音  
  7.              dis=new DataInputStream(new BufferedInputStream(new FileInputStream(recordingFile)));  
  8.             } catch (FileNotFoundException e) {  
  9.               e.printStackTrace();  
  10.             }  
  11.         //最小緩存區  
  12.         int bufferSizeInBytes=AudioTrack.getMinBufferSize(sampleRateInHz,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT);  
  13.         //建立AudioTrack對象   依次傳入 :流類型、採樣率(與採集的要一致)、音頻通道(採集是IN 播放時OUT)、量化位數、最小緩衝區、模式  
  14.         player=new AudioTrack(AudioManager.STREAM_MUSIC,sampleRateInHz,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);  
  15.           
  16.         byte[] data =new byte [bufferSizeInBytes];  
  17.         player.play();//開始播放  
  18.         while(true)  
  19.         {  
  20.             int i=0;  
  21.             try {  
  22.                 while(dis.available()>0&&i<data.length)  
  23.                 {  
  24.                   data[i]=dis.readByte();//錄音時write Byte 那麼讀取時就該爲readByte要相互對應  
  25.                   i++;  
  26.                 }  
  27.             } catch (IOException e) {  
  28.                 // TODO Auto-generated catch block  
  29.                 e.printStackTrace();  
  30.             }  
  31.             player.write(data,0,data.length);  
  32.               
  33.             if(i!=bufferSizeInBytes) //表示讀取完了  
  34.             {  
  35.                 player.stop();//中止播放  
  36.                 player.release();//釋放資源  
  37.                 break;  
  38.             }  
  39.         }  
  40.           
  41.     }  

這裏是播放PCM的關鍵代碼,完整Demo在本文的末尾會給出相應的連接!主要是從文件中讀取數據到數組中,而後寫到AudiotTrack之中,而後AudioTrack就會將其播放,利i!=bufferSizeInBytes 判斷其讀取完了(文件的末尾)。ide

 

3、使用MediaPlayer進行音頻播放。——這個是播放多媒體的,包括audio和 video函數

MediaPlayer是很強大的一個Android系統內置的類,它不只能夠播放音頻同時還能夠播放視頻。最多見的方法有:佈局

start()開始播放        pause()暫停播放    stop()中止播放       prepareAsync() /prepare()  開始準備     

getCurrentPosition() 當前播放的位置         getDuration()文件總的時長      seekTo (int position)定位播放

示例代碼 演示利用MediaPlayer和Seekbar進行音頻 的播放 、暫停、拖動快進播放等 。效果如圖:(具體完整代碼在備註裏面可下載MediaPlayerDemo)

佈局文件:

[html]  view plain  copy
 
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="@drawable/background"  
  6.     tools:context="${relativePackage}.${activityClass}" >  
  7.   
  8.     <TextView   
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content"  
  11.         android:text="天空之城主題曲(宮崎駿)"  
  12.         android:textColor="#F8F8F8"  
  13.         android:textSize="18sp"  
  14.         android:ellipsize="marquee"  
  15.         android:layout_centerInParent="true"  
  16.         />  
  17.       
  18.     <LinearLayout   
  19.         android:layout_width="match_parent"  
  20.         android:layout_height="wrap_content"  
  21.         android:layout_marginLeft="5dp"  
  22.         android:layout_marginRight="5dp"  
  23.         android:layout_marginBottom="5dp"  
  24.         android:layout_above="@+id/bottom"  
  25.         android:gravity="center_vertical"  
  26.         >  
  27.      
  28.     <TextView  
  29.         android:id="@+id/left"  
  30.         android:layout_width="wrap_content"  
  31.         android:layout_height="wrap_content"  
  32.         android:text="00:00"  
  33.         android:textColor="#F8F8F8"  
  34.         />  
  35.       
  36.     <SeekBar   
  37.         android:id="@+id/seek"  
  38.         android:layout_width="match_parent"  
  39.         android:layout_height="wrap_content"  
  40.         android:layout_weight="1"  
  41.         android:enabled="false"  
  42.         />  
  43.      
  44.     <TextView  
  45.         android:id="@+id/right"  
  46.         android:layout_width="wrap_content"  
  47.         android:layout_height="wrap_content"  
  48.         android:text="00:00"  
  49.         android:textColor="#F8F8F8"  
  50.         />  
  51.       
  52.     </LinearLayout>  
  53.       
  54.     <LinearLayout  
  55.         android:id="@+id/bottom"  
  56.         android:layout_width="match_parent"  
  57.         android:layout_height="wrap_content"  
  58.         android:layout_alignParentBottom="true"  
  59.         android:layout_marginBottom="5dp"  
  60.         android:orientation="horizontal" >  
  61.           
  62.         <Button  
  63.             android:id="@+id/start"   
  64.             android:layout_width="0dp"  
  65.             android:layout_height="wrap_content"  
  66.             android:layout_weight="1"  
  67.             android:text="播放"  
  68.             android:textColor="#F8F8F8"  
  69.             android:textSize="14sp"  
  70.             android:enabled="false"  
  71.             />  
  72.           
  73.         <Button  
  74.             android:id="@+id/stop"   
  75.             android:layout_width="0dp"  
  76.             android:layout_height="wrap_content"  
  77.             android:layout_weight="1"  
  78.             android:text="暫停"  
  79.             android:textSize="14sp"  
  80.             android:textColor="#F8F8F8"  
  81.             android:enabled="false"  
  82.             />  
  83.           
  84.     </LinearLayout>  
  85.       
  86. </RelativeLayout>  

 

初始化MediaPlayer

 

[java]  view plain  copy
 
  1.       mAssetManager=getAssets();  
  2. try {  
  3.     afd=mAssetManager.openFd("sky.mp3");// 建立天空之城的AssetFileDescriptor文件  
  4.     } catch (IOException e) {  
  5.     e.printStackTrace();  
  6.     Log.e(TAG,"建立AssetFileDescriptor 異常 ,請查看根福是否存在");  
  7. }  
  8. mMediaPlayer=new MediaPlayer();  
  9. try {  
  10.     //設置播放源 ,固然還有其餘的重載方法 eg:setDataSource(String path) path可使網絡路徑也能夠是本地路徑,網絡的記得加權限  
  11.     mMediaPlayer.setDataSource(afd.getFileDescriptor());   
  12. catch (Exception e) {  
  13.     e.printStackTrace();  
  14.     Log.e(TAG,"設置播放源異常" );  
  15. }  
  16. mMediaPlayer.prepareAsync(); //MediaPlayer 開始準備  異步的, 還有prepare()這個是同步的  

MediaPlayer設置相應的監聽器

 

[java]  view plain  copy
 
  1. seek.setMax(100);//設置長度100  
  2. seek.setOnSeekBarChangeListener(this);//設置Seekbar的滑動監聽器  
  3. mMediaPlayer.setOnPreparedListener(this);//設置準備就緒監聽  
  4. mMediaPlayer.setOnCompletionListener(this);//設置播放完成  
[java]  view plain  copy
 
  1. //結束滑動時     
  2. @Override  
  3. public void onStopTrackingTouch(SeekBar seekBar) {  
  4.       int a=(int)((sum/100.0)*(seekBar.getProgress()));  
  5.       mMediaPlayer.seekTo(a); //seekTo方法接收的單位是:毫秒  
  6.       handler.sendEmptyMessage(START); //更新seekBar  
  7. }  
[java]  view plain  copy
 
  1. @Override  
  2. public void onPrepared(MediaPlayer mp) {  
  3.        //準備就緒完成  
  4.         start.setEnabled(true);  
  5.         stop.setEnabled(true);  
  6.         seek.setEnabled(true);  
  7.         sum=mMediaPlayer.getDuration();  
  8.         right.setText(FormatTime(sum/1000));  }  
[java]  view plain  copy
 
  1. //播放完成  
  2. @Override  
  3. public void onCompletion(MediaPlayer mp) {  
  4.     start.setText("播放");  
  5.     seek.setProgress(0);  
  6.     mMediaPlayer.seekTo(0);  
  7. }  

Handler 更新SeekBar的狀態:

[java]  view plain  copy
 
  1. private Handler handler=new Handler()  
  2.    {  
  3.     @Override  
  4.     public void handleMessage(Message msg) {  
  5.         switch (msg.what) {  
  6.             case 1:{  
  7.                 int current=mMediaPlayer.getCurrentPosition();// 獲得數值的單位是毫秒  
  8.                 int prass=(int)(current/(sum*1.0)*100);  
  9.                 left.setText(FormatTime(current/1000));  
  10.                 seek.setProgress(prass);  
  11.                 if(!pause)  
  12.                 {  
  13.                   handler.sendEmptyMessageDelayed(1,1000);//1 秒後繼續更新  
  14.                 }  
  15.                 break;  
  16.             }  
  17.               
  18.             case 0:{  
  19.                 //中止更新  
  20.                 pause=true;  
  21.                 break;  
  22.             }  
  23.         default:  
  24.             break;  
  25.         }  
  26.     }  
  27.       
  28.    };  

1.比較容易讓人混淆的是pause方法和stop方法的區別:2個方法均可以讓音頻中止。

調用Pause方法後想再次聽見聲音直接調用start方法以後便可。調用stop方法中止音頻以後,再次調用start方法以後不會播放,要先調用prepareAsync或者prepare方法,以後在public void onPrepared(MediaPlayer mp)回調方法裏面調用start方法纔會播放。

2.start方法要在準備就緒,即在public void onPrepared(MediaPlayer mp)裏面回調。

3.不使用MediaPlayer時記得stop,而後release 釋放相關的資源。(本例在Activity的OnDestroy方法中調用的)

下圖是MediaPlayer狀態及方法流程圖:

 

 

 

4、備註:

AudioTrack播放PCMDemo  若是對Demo中音頻採集不熟悉,能夠查閱 Android 音頻採集

MediaPlayerDemo(利用MediaPlayer播放音頻)

相關文章
相關標籤/搜索