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播放音乐的示例,音乐文件是从数据库中取出的。
    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
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;
            }
        }
    };


    /** Called when the activity is first created. */
    @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等。


发布了270 篇原创文章 · 获赞 273 · 访问量 377万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览