播放聲音可以用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
- if (mMediaPlayer == null) {
- mMediaPlayer = new MediaPlayer(); // 建立MediaPlayer對象
- }
- mMediaPlayer.reset();
- String dataSource = getDataByPosition(mCursor, mPlayPosition);
- mMediaPlayer.setDataSource(dataSource); // 設定需要播放的資料源
- mMediaPlayer.prepare(); // 準備播放,如果是流媒體需要調用prepareAsync進行異步準備
- if (Common.PLAY_MODE_SINGLE_LOOP == mPlayMode) {
- mMediaPlayer.setLooping(true); // 單曲循環
- } else {
- mMediaPlayer.setLooping(false); // 不循環播放
- }
- mMediaPlayer.start(); // 開始播放,如果是播放流媒體,需要等到流媒體準備完成才能播放(在prepare的callback函數中調用start進行播放)
- // 根據位置來擷取歌曲位置
- public String getDataByPosition(Cursor c, int position) {
- c.moveToPosition(position);
- int dataColumn = c.getColumnIndex(MediaStore.Audio.Media.DATA);
- String data = c.getString(dataColumn);
- return data;
- }
AudioTrack播放聲音時不能直接把wav檔案傳遞給AudioTrack進行播放,必須傳遞buffer,通過write函數把需要播放的緩沖區buffer傳遞給AudioTrack,然後才能播放。
AudioTrack使用的例子參考下面:
此示例轉自:http://samyou.iteye.com/blog/1125872
[java] view plain copy
- public class AndroidTest extends Activity implements View.OnClickListener,SurfaceHolder.Callback
- {
- private SurfaceHolder surfaceHolder = null;
- private SurfaceView surfaceView = null;
- private AudioTrack audioTrack = null;
- private Thread writePCMThread = null;
- private File audioFile = null;
- private FileInputStream fileInputStream = null;
- private byte buffer[] = new byte[16*10000];
- // The Handler that gets information back from the other threads
- private final Handler msgHandler = new Handler()
- {
- public void handleMessage(Message msg)
- {
- switch (msg.what)
- {
- default:
- break;
- }
- }
- };
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- surfaceView = (SurfaceView) findViewById(R.id.surface);
- SurfaceHolder surfaceHolder = surfaceView.getHolder();
- surfaceHolder.addCallback(this);
- surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- findViewById(R.id.button1).setOnClickListener(this);
- findViewById(R.id.button2).setOnClickListener(this);
- }
- public void finish() {
- super.finish();
- System.out.println("finish");
- try {
- writePCMThread.interrupt();
- } catch (Exception e) {
- }
- try {
- fileInputStream.close();
- } catch (Exception e) {
- }
- try {
- audioTrack.stop();
- audioTrack.release();
- } catch (Exception e) {
- }
- }
- protected void onResume()
- {
- super.onResume();
- System.out.println("back on!!!!!!!!!!!");
- initAudioTrack();
- audioFile = new File(Environment.getExternalStorageDirectory(),"test.wav");
- System.out.println(audioFile.length());
- try {
- fileInputStream = new FileInputStream(audioFile);
- fileInputStream.skip(0x2c);
- } catch (Exception e) {
- }
- writePCMThread = new Thread(new Runnable(){
- public void run() {
- try
- {
- while(fileInputStream.read(buffer)>=0)
- {
- System.out.println("write pcm data");
- audioTrack.write(buffer, 0, buffer.length);
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- });
- }
- private void initAudioTrack()
- {
- int minBufferSize = AudioTrack.getMinBufferSize(0xac44, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
- System.out.println("minBufferSize = "+minBufferSize);
- audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 0xac44,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize*2,AudioTrack.MODE_STREAM);
- audioTrack.setStereoVolume(1.0f, 1.0f);// 設定目前音量大小
- System.out.println("initAudioTrack over");
- audioTrack.play();
- }
- public void onClick(View v)
- {
- switch (v.getId()) {
- case R.id.button1:
- writePCMThread.start();
- break;
- case R.id.button2:
- break;
- default:
- break;
- }
- }
- public void surfaceCreated(SurfaceHolder holder) {
- System.out.println("surfaceCreated()");
- this.surfaceHolder = holder;
- }
- public void surfaceDestroyed(SurfaceHolder holder) {
- }
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- this.surfaceHolder = holder;
- }
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- }
- }
注: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