播放聲音可以用MediaPlayer和AudioTrack,兩者都提供了java API供應(yīng)用開發(fā)者使用。雖然都可以播放聲音,但兩者還是有很大的區(qū)別的。
其中最大的區(qū)別是MediaPlayer可以播放多種格式的聲音文件,例如MP3,AAC,WAV,OGG,MIDI等。MediaPlayer會(huì)在framework層創(chuàng)建對應(yīng)的音頻解碼器。
而AudioTrack只能播放已經(jīng)解碼的PCM流,如果是文件的話只支持wav格式的音頻文件,因?yàn)閣av格式的音頻文件大部分都是PCM流。AudioTrack不創(chuàng)建解碼器,所以只能播放不需要解碼的wav文件。
當(dāng)然兩者之間還是有緊密的聯(lián)系的,MediaPlayer在framework層還是會(huì)創(chuàng)建AudioTrack,把解碼后的PCM數(shù)流傳遞給AudioTrack,AudioTrack再傳遞給AudioFlinger進(jìn)行混音,然后才傳遞給硬件播放。
所以是MediaPlayer包含了AudioTRack。
通過查看API可以知道,MediaPlayer提供了5個(gè)setDataSource方法,分為三類,一類是傳遞播放文件的字符串路徑作為參數(shù),例如直接取sd卡里mp3文件的路徑,一類是傳遞播放文件的FileDescriptor文件描述符作為播放的id,例例如從db中查詢的音頻文件的id,就可以直接賦給MediaPlayer進(jìn)行播放。還有一類是Uri類型的資源文件,用于播放content uri文件。
下面是一個(gè)用MediaPlayer播放音樂的示例,音樂文件是從數(shù)據(jù)庫中取出的。
- if (mMediaPlayer == null) {
- mMediaPlayer = new MediaPlayer();
- }
-
- mMediaPlayer.reset();
- String dataSource = getDataByPosition(mCursor, mPlayPosition);
- mMediaPlayer.setDataSource(dataSource);
- mMediaPlayer.prepare();
- if (Common.PLAY_MODE_SINGLE_LOOP == mPlayMode) {
- mMediaPlayer.setLooping(true);
- } else {
- mMediaPlayer.setLooping(false);
- }
- mMediaPlayer.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播放聲音時(shí)不能直接把wav文件傳遞給AudioTrack進(jìn)行播放,必須傳遞buffer,通過write函數(shù)把需要播放的緩沖區(qū)buffer傳遞給AudioTrack,然后才能播放。
AudioTrack使用的例子參考下面:
此示例轉(zhuǎn)自:http://samyou.iteye.com/blog/1125872
- 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];
-
-
- 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是一種數(shù)據(jù)編碼格式,CD唱盤上刻錄的就直接用pcm格式編碼的數(shù)據(jù)文件;
wav是一種聲音文件格式,wav里面包含的聲音數(shù)據(jù)可以是采用pcm格式編碼的聲音數(shù)據(jù),也可以是采用其它格式編碼的聲音數(shù)據(jù),但目前一般采用pcm編碼的聲音數(shù)據(jù)
兩者區(qū)別就是這些
pcm是一個(gè)通信上的概念,脈沖編碼調(diào)制。wav是媒體概念,體現(xiàn)的是封裝。wav文件可以封裝pcm編碼信息,也可以封裝其他編碼格式,例如mp3等。