標籤:
Android平台播放音訊方式一般有3種。1.利用系統內建的應用程式播放音頻 2.利用AudioTrack播放原始音頻 3.使用MediaPlayer播放。此3種音頻播放方式,以第三種MediaPlayer播放這種方式使用的最多,必須掌握!
一、使用系統內建的程式。
Google想的“周到”,一般都給我們提供了一些內建程式,然而這些內建程式的UI效果,那真是感人啊!一般內建程式,我們就是看看而已。
Intent intent=new Intent(Intent.ACTION_VIEW);intent.setDataAndType(url,type); //eg:intent.setDataAndType(url,“audio/mp3”); url音頻檔案路徑startActivity(intent);
二、使用AudioTrack播放音頻
AudioTrack只能用來播放原始音頻(PCM)
//播放音頻(PCM)public void play(){ DataInputStream dis=null;try { //從音頻檔案中讀取聲音 dis=new DataInputStream(new BufferedInputStream(new FileInputStream(recordingFile))); } catch (FileNotFoundException e) { e.printStackTrace(); }//最小緩衝區int bufferSizeInBytes=AudioTrack.getMinBufferSize(sampleRateInHz,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT);//建立AudioTrack對象 依次傳入 :流類型、採樣率(與採集的要一致)、音頻通道(採集是IN 播放時OUT)、量化位元、最小緩衝區、模式 player=new AudioTrack(AudioManager.STREAM_MUSIC,sampleRateInHz,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM);byte[] data =new byte [bufferSizeInBytes];player.play();//開始播放while(true){int i=0; try {while(dis.available()>0&&i<data.length){ data[i]=dis.readByte();//錄音時write Byte 那麼讀取時就該為readByte要相互對應 i++;}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} player.write(data,0,data.length); if(i!=bufferSizeInBytes) //表示讀取完了 { player.stop();//停止播放 player.release();//釋放資源 break; }}}這裡是播放PCM的關鍵代碼,完整Demo在本文的末尾會給出相應的連結!主要是從檔案中讀取資料到數組中,然後寫到AudiotTrack之中,然後AudioTrack就會將其播放,利i!=bufferSizeInBytes 判斷其讀取完了(檔案的末尾)。
三、使用MediaPlayer進行音頻播放。
MediaPlayer是很強大的一個android系統內建的類,它不僅可以播放音頻同時還可以播放視頻。最常見的方法有:
start()開始播放 pause()暫停播放 stop()停止播放 prepareAsync() /prepare() 開始準備
getCurrentPosition() 當前播放的位置 getDuration()檔案總的時間長度 seekTo (int position)定位播放
範例程式碼 示範利用MediaPlayer和Seekbar進行音頻 的播放 、暫停、拖動快進播放等 。效果(具體完整代碼在備忘裡面可下載MediaPlayerDemo)
布局檔案:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/background" tools:context="${relativePackage}.${activityClass}" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="天空之城主題曲(宮崎駿)" android:textColor="#F8F8F8" android:textSize="18sp" android:ellipsize="marquee" android:layout_centerInParent="true" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_marginBottom="5dp" android:layout_above="@+id/bottom" android:gravity="center_vertical" > <TextView android:id="@+id/left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00:00" android:textColor="#F8F8F8" /> <SeekBar android:id="@+id/seek" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:enabled="false" /> <TextView android:id="@+id/right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00:00" android:textColor="#F8F8F8" /> </LinearLayout> <LinearLayout android:id="@+id/bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="5dp" android:orientation="horizontal" > <Button android:id="@+id/start" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="播放" android:textColor="#F8F8F8" android:textSize="14sp" android:enabled="false" /> <Button android:id="@+id/stop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="暫停" android:textSize="14sp" android:textColor="#F8F8F8" android:enabled="false" /> </LinearLayout> </RelativeLayout>
初始化MediaPlayer
mAssetManager=getAssets();try {afd=mAssetManager.openFd("sky.mp3");// 建立天空之城的AssetFileDescriptor檔案 } catch (IOException e) {e.printStackTrace();Log.e(TAG,"建立AssetFileDescriptor 異常 ,請查看根福是否存在");}mMediaPlayer=new MediaPlayer();try {//設定播放源 ,當然還有其他的重載方法 eg:setDataSource(String path) path可以使網路路徑也可以是本地路徑,網路的記得加許可權mMediaPlayer.setDataSource(afd.getFileDescriptor()); } catch (Exception e) {e.printStackTrace();Log.e(TAG,"設定播放源異常" );}mMediaPlayer.prepareAsync(); //MediaPlayer 開始準備 非同步, 還有prepare()這個是同步的
MediaPlayer設定相應的監聽器
seek.setMax(100);//設定長度100 seek.setOnSeekBarChangeListener(this);//設定Seekbar的滑動監聽器 mMediaPlayer.setOnPreparedListener(this);//設定準備就緒監聽 mMediaPlayer.setOnCompletionListener(this);//設定播放完成
//結束滑動時 @Overridepublic void onStopTrackingTouch(SeekBar seekBar) { int a=(int)((sum/100.0)*(seekBar.getProgress())); mMediaPlayer.seekTo(a); //seekTo方法接收的單位是:毫秒 handler.sendEmptyMessage(START); //更新seekBar}
@Override public void onPrepared(MediaPlayer mp) { //準備就緒完成 start.setEnabled(true); stop.setEnabled(true); seek.setEnabled(true); sum=mMediaPlayer.getDuration(); right.setText(FormatTime(sum/1000)); }
//播放完成@Overridepublic void onCompletion(MediaPlayer mp) {start.setText("播放");seek.setProgress(0);mMediaPlayer.seekTo(0);}Handler 更新SeekBar的狀態:
private Handler handler=new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) { case 1:{ int current=mMediaPlayer.getCurrentPosition();// 得到數值的單位是毫秒 int prass=(int)(current/(sum*1.0)*100); left.setText(FormatTime(current/1000)); seek.setProgress(prass); if(!pause) { handler.sendEmptyMessageDelayed(1,1000);//1 秒後繼續更新 } break; } case 0:{ //停止更新 pause=true; break; }default:break;}} };
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狀態及方法流程圖:
四、備忘:
AudioTrack播放PCMDemo 如果對Demo中音頻採集不熟悉,可以查閱 Android 音頻採集
MediaPlayerDemo(利用MediaPlayer播放音頻)
Android 音頻播放