天天看點

MediaPlayer和AudioTrack播放Audio的差別與聯系

播放聲音可以用MediaPlayer和AudioTrack,兩者都提供了java API供應用開發者使用。雖然都可以播放聲音,但兩者還是有很大的差別的。

其中最大的差別是MediaPlayer可以播放多種格式的聲音檔案,例如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer會在framework層建立對應的音頻解碼器。

而AudioTrack隻能播放已經解碼的PCM流,如果是檔案的話隻支援wav格式的音頻檔案,因為wav格式的音頻檔案大部分都是PCM流。AudioTrack不建立解碼器,是以隻能播放不需要解碼的wav檔案。

當然兩者之間還是有緊密的聯系的,MediaPlayer在framework層還是會建立AudioTrack,把解碼後的PCM數流傳遞給AudioTrack,AudioTrack再傳遞給AudioFlinger進行混音,然後才傳遞給硬體播放。

是以是MediaPlayer包含了AudioTRack。

通過檢視API可以知道,MediaPlayer提供了5個setDataSource方法,分為三類,一類是傳遞播放檔案的字元串路徑作為參數,例如直接取sd卡裡mp3檔案的路徑,一類是傳遞播放檔案的FileDescriptor檔案描述符作為播放的id,例例如從db中查詢的音頻檔案的id,就可以直接賦給MediaPlayer進行播放。還有一類是Uri類型的資源檔案,用于播放content uri檔案。

下面是一個用MediaPlayer播放音樂的示例,音樂檔案是從資料庫中取出的。

[java]  view plain  copy

  1. if (mMediaPlayer == null) {  
  2.     mMediaPlayer = new MediaPlayer(); // 建立MediaPlayer對象  
  3. }  
  4. mMediaPlayer.reset();  
  5. String dataSource = getDataByPosition(mCursor, mPlayPosition);  
  6. mMediaPlayer.setDataSource(dataSource); // 設定需要播放的資料源  
  7. mMediaPlayer.prepare(); // 準備播放,如果是流媒體需要調用prepareAsync進行異步準備  
  8. if (Common.PLAY_MODE_SINGLE_LOOP == mPlayMode) {  
  9.     mMediaPlayer.setLooping(true); // 單曲循環  
  10. } else {  
  11.     mMediaPlayer.setLooping(false); // 不循環播放  
  12. }  
  13. mMediaPlayer.start(); // 開始播放,如果是播放流媒體,需要等到流媒體準備完成才能播放(在prepare的callback函數中調用start進行播放)  
  14. // 根據位置來擷取歌曲位置  
  15. public String getDataByPosition(Cursor c, int position) {  
  16.     c.moveToPosition(position);  
  17.     int dataColumn = c.getColumnIndex(MediaStore.Audio.Media.DATA);  
  18.     String data = c.getString(dataColumn);  
  19.     return data;  
  20. }  

AudioTrack播放聲音時不能直接把wav檔案傳遞給AudioTrack進行播放,必須傳遞buffer,通過write函數把需要播放的緩沖區buffer傳遞給AudioTrack,然後才能播放。

AudioTrack使用的例子參考下面:

此示例轉自:http://samyou.iteye.com/blog/1125872

[java]  view plain  copy

  1. public class AndroidTest extends Activity implements View.OnClickListener,SurfaceHolder.Callback  
  2. {  
  3.     private SurfaceHolder surfaceHolder = null;  
  4.     private SurfaceView surfaceView = null;  
  5.     private AudioTrack audioTrack = null;  
  6.     private Thread writePCMThread = null;  
  7.     private File audioFile = null;  
  8.     private FileInputStream fileInputStream = null;  
  9.     private byte buffer[] = new byte[16*10000];  
  10.     // The Handler that gets information back from the other threads  
  11.     private final Handler msgHandler = new Handler()  
  12.     {  
  13.         public void handleMessage(Message msg)  
  14.         {  
  15.             switch (msg.what)  
  16.             {  
  17.             default:  
  18.                 break;  
  19.             }  
  20.         }  
  21.     };  
  22.     @Override  
  23.     public void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.main);  
  26.         surfaceView = (SurfaceView) findViewById(R.id.surface);  
  27.         SurfaceHolder surfaceHolder = surfaceView.getHolder();  
  28.         surfaceHolder.addCallback(this);  
  29.         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  30.         findViewById(R.id.button1).setOnClickListener(this);  
  31.         findViewById(R.id.button2).setOnClickListener(this);  
  32.     }  
  33.     public void finish() {  
  34.         super.finish();  
  35.         System.out.println("finish");  
  36.         try {  
  37.             writePCMThread.interrupt();  
  38.         } catch (Exception e) {  
  39.         }  
  40.         try {  
  41.             fileInputStream.close();  
  42.         } catch (Exception e) {  
  43.         }  
  44.         try {  
  45.             audioTrack.stop();  
  46.             audioTrack.release();  
  47.         } catch (Exception e) {  
  48.         }  
  49.     }  
  50.     protected void onResume()  
  51.     {  
  52.         super.onResume();  
  53.         System.out.println("back on!!!!!!!!!!!");  
  54.         initAudioTrack();  
  55.         audioFile = new File(Environment.getExternalStorageDirectory(),"test.wav");  
  56.         System.out.println(audioFile.length());  
  57.         try {  
  58.             fileInputStream = new FileInputStream(audioFile);  
  59.             fileInputStream.skip(0x2c);  
  60.         } catch (Exception e) {  
  61.         }  
  62.         writePCMThread = new Thread(new Runnable(){  
  63.             public void run() {  
  64.                 try  
  65.                 {  
  66.                     while(fileInputStream.read(buffer)>=0)  
  67.                     {  
  68.                         System.out.println("write pcm data");  
  69.                         audioTrack.write(buffer, 0, buffer.length);  
  70.                     }  
  71.                 }  
  72.                 catch (Exception e) {  
  73.                     e.printStackTrace();  
  74.                 }  
  75.             }  
  76.         });  
  77.     }  
  78.     private void initAudioTrack()  
  79.     {  
  80.         int minBufferSize = AudioTrack.getMinBufferSize(0xac44, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);  
  81.         System.out.println("minBufferSize = "+minBufferSize);  
  82.         audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 0xac44,  
  83.         AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize*2,AudioTrack.MODE_STREAM);  
  84.         audioTrack.setStereoVolume(1.0f, 1.0f);// 設定目前音量大小  
  85.         System.out.println("initAudioTrack over");  
  86.         audioTrack.play();  
  87.     }  
  88.     public void onClick(View v)  
  89.     {  
  90.         switch (v.getId()) {  
  91.         case R.id.button1:  
  92.             writePCMThread.start();  
  93.             break;  
  94.         case R.id.button2:  
  95.             break;  
  96.         default:  
  97.             break;  
  98.     }  
  99.     }  
  100.     public void surfaceCreated(SurfaceHolder holder) {  
  101.         System.out.println("surfaceCreated()");  
  102.         this.surfaceHolder = holder;  
  103.     }  
  104.     public void surfaceDestroyed(SurfaceHolder holder) {  
  105.     }  
  106.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  107.         int height) {  
  108.         this.surfaceHolder = holder;  
  109.     }  
  110.     public void onActivityResult(int requestCode, int resultCode, Intent data) {  
  111.     }  
  112. }  

注:PCM和WAV

以下摘自:http://www.erji.net/read.php?tid=227570

簡單來說,pcm是一種資料編碼格式,CD唱盤上刻錄的就直接用pcm格式編碼的資料檔案;

wav是一種聲音檔案格式,wav裡面包含的聲音資料可以是采用pcm格式編碼的聲音資料,也可以是采用其它格式編碼的聲音資料,但目前一般采用pcm編碼的聲音資料

兩者差別就是這些

pcm是一個通信上的概念,脈沖編碼調制。wav是媒體概念,展現的是封裝。wav檔案可以封裝pcm編碼資訊,也可以封裝其他編碼格式,例如mp3等。

轉載至:http://blog.csdn.net/ameyume/article/details/7618820