自定义MediaPlayer(一) -- 关于MediaPlayer的碎碎念

一、 不可复用的MediaPlayer
MediaPlayer,对每个android开发者来说,都不陌生。
简单的调用

mMediaPlayer = new MediaPlayer(); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.setOnErrorListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnInfoListener(this); mMediaPlayer.setDataSource(this.mUrlString); mMediaPlayer.prepareAsync();


这几段代码,调用起来也是得心应手。对于简单的歌曲播放,确实满足了平常应用的开发。


可是,程序员的天敌 -- 策划大爷,他们就看不得你们这么安逸的Working。
现在问题来了,策划说要对音频文件分段加密,意味着我们就是要边解密边播放了。
带着这个问题,我开始研究MediaPlayer,看看能不能一段一段文件播放。结果自然是没有了。。

setDataSource(String path); //设置文件的路径 setDataSource(FileDescriptor fd); //设置文件的流标识


最最无奈的是,MediaPlayer是用C++编写的。不就是操作流文件嘛。干嘛写的这么复杂而且还没办法自定义。
二、寻找新的MediaPlayer
无奈归无奈,功能还是要去实现的。谁让我们是快乐的IT民工呢!
好吧,开始,google,等待浏览器缓冲,开启有道翻译!
http://stackoverflow.com/questions/10060165/android-mediaplayer-buffer-size-in-ics-4-0
这是不错的方案,就是麻烦了点。自己搭建一个SocketService,Service读取服务器上的流文件传给MediaPlayer播放。
大体就是:

1. MediaPlayer.SetDataSource("127.0.0.1:123456"); 2. stream = inputStream.read(); 3. buff = decode(stream); //解密 4. output.write(buff, 0, readBytes);



这是个不错的方案。但是操作起来就麻烦了。音乐盒播放器,经常要切换歌曲,每次切换歌曲都要去对Socket和MediaPlay经常操作,就会产生很多的异步问题。给自己增加无数的bug。。。。
将Socket的方案保留,做个备胎。
三、 开源的Android,没有不能实现的功能
有没有类似,outputStream.write的方式呢?就是不断的解码,然后不断的写入流,最后底层系统不断的播放音频流。
经过一定的努力,找到了AudioTrack类。
http://www.cnblogs.com/innost/archive/2011/01/09/1931457.html

trackplayer.write(bytes_pkg, 0, bytes_pkg.length) ; //往track中写数据

看到这段代码,所有的问题都引刃而解了。
四、神奇的AudioTrack
AudioTrack类实现将音频数据输出到音频设备中。
该类的SDK文档是如下描述的:
The AudioTrack class manages and plays a single audio resource for Java applications. It allows streaming of PCM audio buffers to the audio sink for playback. This is achieved by "pushing" the data to the AudioTrack object using one of the write(byte[], int, int), write(short[], int, int), and write(float[], int, int, int) methods.
以下再摘自网上的一段代码,结束本篇幅:
【自定义MediaPlayer(一) -- 关于MediaPlayer的碎碎念】
//根据采样率,采样精度,单双声道来得到frame的大小。int bufsize = AudioTrack.getMinBufferSize(8000,//每秒8K个点 AudioFormat.CHANNEL_CONFIGURATION_STEREO,//双声道 AudioFormat.ENCODING_PCM_16BIT); //一个采样点16比特-2个字节 //注意,按照数字音频的知识,这个算出来的是一秒钟buffer的大小。 //创建AudioTrack AudioTrack trackplayer = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_ STEREO, AudioFormat.ENCODING_PCM_16BIT, bufsize, AudioTrack.MODE_STREAM); // trackplayer.play() ; //开始 trackplayer.write(bytes_pkg, 0, bytes_pkg.length) ; //往track中写数据 …. trackplayer.stop(); //停止播放 trackplayer.release(); //释放底层资源。


    推荐阅读