Android中播放音乐的几种方式(2)

电脑杂谈  发布时间:2019-08-26 23:03:20  来源:网络整理
AudioTrack属于更偏底层的音频播放,MediaPlayerService的内部就是使用了AudioTrack。
AudioTrack用于单个音频播放和管理,相比于MediaPlayer具有:精炼、高效的优点。
更适合实时产生播放数据的情况,如加密的音频,
MediaPlayer是束手无策的,AudioTrack却可以。
AudioTrack用于播放PCM(PCM无压缩的音频格式)音乐流的回放,
如果需要播放其它格式音频,需要响应的,
这也是AudioTrack用的比较少的原因,需要自己解码音频。

静态模式—static

静态的言下之意就是数据一次付给接收方。好处是简单高效,只应该进行一次操作就完成了数据的释放;缺点也许也很明显,对于数据量较大的音频回放,显然它是能够胜任的,因而往往只用于播放铃声、系统提示等对内存小的操作

流模式streaming

流方式和网络上播放视频是类似的,即数据是根据一定规律不断地传递给接收方的。理论上它可用于任何音频播放的画面,不过我们通常在下面情况下采取:

通过write(byte[], int, int), write(short[], int, int)
write(float[], int, int, int)等方法推送解码数据到AudioTrack
private void jetPlayStream(){
        new Thread(new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.M)
            @Override
            public void run() {
                // 获取最小缓冲区
                int bufSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
                // 实例化AudioTrack(设置缓冲区为最小缓冲区的2倍,至少要等于最小缓冲区)
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
                        AudioFormat.ENCODING_PCM_16BIT, bufSize*2, AudioTrack.MODE_STREAM);
                // 设置音量
                audioTrack.setVolume(2f) ;
                // 设置播放频率
                audioTrack.setPlaybackRate(10) ;
                audioTrack.play();
                // 获取音乐文件输入流
                InputStream is = getResources().openRawResource(R.raw.zbc);
                byte[] buffer = new byte[bufSize*2] ;
                int len ;
                try {
                    while((len=is.read(buffer,0,buffer.length)) != -1){
                        System.out.println("读取数据中...");
                        // 将读取的数据,写入Audiotrack
                        audioTrack.write(buffer,0,buffer.length) ;
                    }
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

更深入的探究,请参考下面博客

android 音频播放框架_android ios 音频格式_android 音频播放

从名字就可看出AsyncPlayer属于异步播放器,官方给出的表明是:所有工作都在子线程进行,不影响读取线程任何操作。

AsyncPlayer就是对MediaPlayer的一次简单的封装,对MediaPlaer所有的操作都在新开线程中执行。

AsyncPlayer只合适简单的异步播放,不能控制进度,只能开始或中止播放。如果播放在此调用play()方法,AsyncPlayer会停止当前播放,开始新的播放。

播放源码


/**
*内部线程类
**/
private final class Thread extends java.lang.Thread {
        public void run() {
            while (true) {
                Command cmd = null;
                synchronized (mCmdQueue) {
                    //取出链表中新加入的cmd
                    cmd = mCmdQueue.removeFirst();
                }
                switch (cmd.code) {
                case PLAY:
                    if (mDebug) Log.d(mTag, "PLAY");
                    //调用MediaPlayer播放
                    startSound(cmd);
                    break;
                }
                ....
            }
        }
    }
 private void startSound(Command cmd) {
        // Preparing can be slow, so if there is something else
        // is playing, let it continue until we're done, so 
            if (mDebug) Log.d(mTag, "Starting playback");
            MediaPlayer player = new MediaPlayer();
            player.setAudioStreamType(cmd.stream);
            player.setDataSource(cmd.context, cmd.uri);
            player.setLooping(cmd.looping);
            player.prepare();
            player.start();
            ....
    }
十分简单,不再贴出,可以在文末Demo中看到

Jet是由OHA联盟成员SONiVOX开发的一个交互音乐引擎。其包含两个别:JET播放器和JET引擎。JET常用于控制游戏的声音特效,采用MIDI(Musical Instrument Digital Interface)格式。

ps:以后碰到手机中的”.jet”文件,就只到它到底是哪个东东了。。。

//获取JetPlayer播放器
JetPlayer mJet = JetPlayer.getJetPlayer() ;
// 清空分段队列,并清除所有要进行播放的剪辑。
1. boolean clearQueue()  //每次播放前,记得做一次清空操作
// 加载jet文件的方法
2. boolean loadJetFile(String path)
   boolean loadJetFile(AssetFileDescriptor afd)
// 开始播放
3. boolean play()
// 暂停播放
4. boolean pause()
// 释放资源
5. void release()
// 指定jet队列的播放序列(调用play()前需要调用此方法)
6. boolean queueJetSegment(int segmentNum, int libNum, int repeatCount, int transpose, int muteFlags, byte userID)
private void jetPlayer(){
        // 获取JetPlayer播放器
        JetPlayer mJet = JetPlayer.getJetPlayer() ;
        //清空播放队列
        mJet.clearQueue() ;
        //绑定事件
        mJet.setEventListener(new JetPlayer.OnJetEventListener() {
            //播放次数记录
            int playNum = 1 ;
            @Override
            public void onJetEvent(JetPlayer player, short segment, byte track, byte channel, byte controller, byte value) {
                Log.i(TAG,"----->onJetEvent") ;
            }
            @Override
            public void onJetUserIdUpdate(JetPlayer player, int userId, int repeatCount) {
                Log.i(TAG,"----->onJetUserIdUpdate") ;
            }
            @Override
            public void onJetNumQueuedSegmentUpdate(JetPlayer player, int nbSegments) {
                Log.i(TAG,"----->onJetNumQueuedSegmentUpdate") ;
            }
            @Override
            public void onJetPauseUpdate(JetPlayer player, int paused) {
                Log.i(TAG,"----->onJetPauseUpdate") ;
                if(playNum == 2){
                    playNum = -1 ;
                    //释放资源,并关闭jet文件
                    player.release();
                    player.closeJetFile() ;
                }else{
                    playNum++ ;
                }
            }
        });
        //加载资源
        mJet.loadJetFile(getResources().openRawResourceFd(R.raw.level1)) ;
        byte sSegmentID = 0 ;
        //指定播放序列
        mJet.queueJetSegment(0, 0, 0, 0, 0, sSegmentID);
        mJet.queueJetSegment(1, 0, 1, 0, 0, sSegmentID);
        //开始播放
        mJet.play() ;
    }


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-120691-2.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...