播放声音可以用 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 播放音乐的示例,音乐文件是从数据库中取出的。
- 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 播放声音时不能直接把 wav 文件传递给 AudioTrack 进行播放,必须传递 buffer,通过 write 函数把需要播放的缓冲区 buffer 传递给 AudioTrack,然后才能播放。
AudioTrack 使用的例子参考下面:
此示例转自:
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 是一种数据编码格式,CD 唱盘上刻录的就直接用 pcm 格式编码的数据文件;
wav 是一种声音文件格式,wav 里面包含的声音数据可以是采用 pcm 格式编码的声音数据,也可以是采用其它格式编码的声音数据,但目前一般采用 pcm 编码的声音数据
两者区别就是这些。
pcm 是一个通信上的概念,脉冲编码调制。wav 是媒体概念,体现的是封装。wav 文件可以封装 pcm 编码信息,也可以封装其他编码格式,例如 mp3 等。
【原文链接】
[1] 《MediaPlayer和AudioTrack播放Audio的区别与联系》