Android中播放音频六种方式 您所在的位置:网站首页 播放程序什么 Android中播放音频六种方式

Android中播放音频六种方式

2024-07-06 17:10| 来源: 网络整理| 查看: 265

一. MediaPlayer:

MediaPlayer确实强大,提供了对音频播放的各种控制,生命周期: 在这里插入图片描述

1. MediaPlayer支持:AAC、AMR、FLAC、MP3、MIDI、OGG、PCM等格式 2. 播放Raw下的元数据 mMediaPlayer=MediaPlayer.create(this, R.raw.audio); mMediaPlayer.start(); 3. MediaPlayer设置播放源的4中方式 setDataSource (String path) //从sd卡中加载音乐 mMediaPlayer.setDataSource("../music/samsara.mp3") ; //从网路加载音乐 mMediaPlayer.setDataSource("http://..../xxx.mp3") ; //需使用异步缓冲 mMediaPlayer.prepareAsync() ; setDataSource (FileDescriptor fd) //需将资源文件放在assets文件夹 AssetFileDescriptor fd = getAssets().openFd("samsara.mp3"); mMediaPlayer.setDataSource(fd) mMediaPlayer.prepare() ; Ps:此方法系统需大于等于android setDataSource (Context context, Uri uri) 这个方法没什么好说的,一般通过ContentProvider获取Android系统提供的共享music获取uri,然后设置数据播放setDataSource (FileDescriptor fd, long offset, long length) //需将资源文件放在assets文件夹 AssetFileDescriptor fd = getAssets().openFd("samsara.mp3"); mMediaPlayer.setDataSource(fd, fd.getStartOffset(), fd.getLength()) mMediaPlayer.prepare() ; 注意点

设置完数据源,不要忘记prepare(),尽量使用异步prepareAync(),这样不会阻塞UI线程。 播放完毕即使释放资源

mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null;

不足:资源占用量较高、延迟时间较长、不支持多个音频同时播放等

demo:

//创建MediaPlayer和设置监听 mPlayer = new MediaPlayer() ; mSeekBar.setOnSeekBarChangeListener(new MySeekBarChangeListener()); mPlayer.setOnPreparedListener(new MyOnPrepareListener()); mPlayer.setOnCompletionListener(new MyOnCompletionListener()); /** * 从assets资源文件夹中播放 * @param name */ private void playSoundFromA(String name) { if (mPlayer.isPlaying()) { mPlayer.stop(); } // 设置当前播放歌曲的名字 title.setText(names[current]); mPlayer.reset(); AssetFileDescriptor afd = getAssetFileDescriptor(name); try { mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); hasResource = true; mPlayer.prepareAsync(); } catch (IOException e) { e.printStackTrace(); } } 二. SoundPool播放音频

SoundPool支持多个音频文件同时播放(组合音频也是有上限的),延时短,比较适合短促、密集的场景,是游戏开发中音效播放的福音。

1. SoundPool实例化方式 new SoundPool(适用与5.0以下) SoundPool(int maxStreams, int streamType, int srcQuality) 从android5.0开始此方法被标记为过时,稍微说以下几个参数。 1.maxStreams :允许同时播放的流的最大值 2.streamType :音频流的类型描述, 在Audiomanager中有种类型声明,游戏应用通常会使用流媒体音乐。 2. srcQuality:采样率转化质量 SoundPool.Builder(从5.0开始支持) //设置描述音频流信息的属性 AudioAttributes abs = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build() ; SoundPool mSoundPoll = new SoundPool.Builder() .setMaxStreams(100) //设置允许同时播放的流的最大值 .setAudioAttributes(abs) //完全可以设置为null .build() ; 重要的方法 // 几个load方法和上文提到的MediaPlayer基本一致,不做多的解释 //------------------------------------------------------------ int load(AssetFileDescriptor afd, int priority) int load(Context context, int resId, int priority) int load(String path, int priority) int load(FileDescriptor fd, long offset, long length, int priority) //------------------------------------------------------------- // 通过流id暂停播放 final void pause(int streamID) // 播放声音,soundID:音频id; left/rightVolume:左右声道(默认1,1);loop:循环次数(-1无限循环);rate:播放速率(1为标准) final int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) //释放资源(很重要) final void release() //恢复播放 final void resume(int streamID) //设置指定id的音频循环播放次数 final void setLoop(int streamID, int loop) //设置加载监听(因为加载是异步的,需要监听加载,完成后再播放) void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener) //设置优先级(同时播放个数超过最大值时,优先级低的先被移除) final void setPriority(int streamID, int priority) //设置指定音频的播放速率,0.5~2.0(rate>1:加快播放,反之慢速播放) final void setRate(int streamID, float rate) //停止指定音频播放 final void stop(int streamID) //卸载指定音频 final boolean unload(int soundID) //暂停所有音频的播放 final void autoPause() //恢复所有暂停的音频播放 final void autoResum()

以上方法基本上是SoundPool的所有方法了,也都很常用。

2个概念 看了Sounpool的api,是不是感觉对 streamID 和 soundID 一脸懵逼? soundID:加载音乐资源时的返回值,int load(String path, int priority),这个int返回值就是soundIDstreamID:播放时返回的值,即play()方法的返回值 demo 注:我把SoundPool做了简单封装,SoundPoolUtil,会在文末上传, 有兴趣可下载看一下,时间比较急,还有很多不足的地方 //初始化SoundPool if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ AudioAttributes aab = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ; mSoundPool = new SoundPool.Builder() .setMaxStreams(10) .setAudioAttributes(aab) .build() ; }else{ mSoundPool = new SoundPool(60, AudioManager.STREAM_MUSIC,8) ; } mSoundPool = new SoundPool(60, AudioManager.STREAM_MUSIC,8) ; //设置资源加载监听 mSoundPool.setOnLoadCompleteListener(new MyOnLoadCompleteListener()); //加载资源 /** * 加载指定路径列表的资源 * @param map */ public void loadR(Map map){ Set entries = map.entrySet(); for(Map.Entry entry : entries){ String key = entry.getKey() ; if(checkSoundPool()){ if(!idCache.containsKey(key)){ idCache.put(key, mSoundPool.load(entry.getValue(),1)) ; } } } } /** * 播放指定音频,并返用于停止、暂停、恢复的StreamId * @param name * @param times * @return */ public int play(String name, int times){ return this.play(name,1,1,1,times,1) ; } 三. AudioTrack播放音频

AudioTrack属于更偏底层的音频播放,MediaPlayerService的内部就是使用了AudioTrack。

AudioTrack用于单个音频播放和管理,相比于MediaPlayer具有:精炼、高效的优点。 更适合实时产生播放数据的情况,如加密的音频, MediaPlayer是束手无策的,AudioTrack却可以。

AudioTrack用于播放PCM(PCM无压缩的音频格式)音乐流的回放, 如果需要播放其它格式音频,需要响应的解码器, 这也是AudioTrack用的比较少的原因,需要自己解码音频。

1. AudioTreack的2种播放模式

静态模式—static

静态的言下之意就是数据一次性交付给接收方。好处是简单高效,只需要进行一次操作就完成了数据的传递;缺点当然也很明显,对于数据量较大的音频回放,显然它是无法胜任的,因而通常只用于播放铃声、系统提醒等对内存小的操作

流模式streaming

流模式和网络上播放视频是类似的,即数据是按照一定规律不断地传递给接收方的。理论上它可用于任何音频播放的场景,不过我们一般在以下情况下采用:

音频文件过大

音频属性要求高,比如采样率高、深度大的数据

音频数据是实时产生的,这种情况就只能用流模式了

通过write(byte[], int, int), write(short[], int, int) write(float[], int, int, int)等方法推送解码数据到AudioTrack

Demo

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(); } 四. AsyncPlayer播放音频

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

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

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

五. JetPlayer播放音频

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

//获取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)

Demo

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() ; } 六. Ringtone

Ringtone为铃声、通知和其他类似声音提供快速播放的方法,这里还不得不提到一个管理类”RingtoneManager”,提供系统铃声列表检索方法,并且,Ringtone实例需要从RingtoneManager获取。

获取实例

获取实例方法,均为RingtoneManager类提供 //通过铃声uri获取 static Ringtone getRingtone(Context context, Uri ringtoneUri) //通过铃声检索位置获取 Ringtone getRingtone(int position)

其实,Rington这个类比较简单,只需要掌握,播放、停止(paly(),stop())等方法就可以了,而RingtoneManager却是比较重要的。 重要方法

1. // 两个构造方法 RingtoneManager(Activity activity) RingtoneManager(Context context) 2. // 获取指定声音类型(铃声、通知、闹铃等)的默认声音的Uri static Uri getDefaultUri(int type) 3. // 获取系统所有Ringtone的cursor Cursor getCursor() 4. // 获取cursor指定位置的Ringtone uri Uri getRingtoneUri(int position) 5. // 判断指定Uri是否为默认铃声 static boolean isDefault(Uri ringtoneUri) 6. //获取指定uri的所属类型 static int getDefaultType(Uri defaultRingtoneUri) 7. //将指定Uri设置为指定声音类型的默认声音 static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri)

从api看,Ringtone和RingtoneManager还是比较简单的,不多做解释了,直接放上一段使用代码。

/** * 播放来电铃声的默认音乐 */ private void playRingtoneDefault(){ Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) ; Ringtone mRingtone = RingtoneManager.getRingtone(this,uri); mRingtone.play(); } /** * 随机播放一个Ringtone(有可能是提示音、铃声等) */ private void ShufflePlayback(){ RingtoneManager manager = new RingtoneManager(this) ; Cursor cursor = manager.getCursor(); int count = cursor.getCount() ; int position = (int)(Math.random()*count) ; Ringtone mRingtone = manager.getRingtone(position) ; mRingtone.play(); } //记得添加下面两个权限 筛选方案:

对于延迟度要求不高,并且希望能够更全面的控制音乐的播放,MediaPlayer比较适合

声音短小,延迟度小,并且需要几种声音同时播放的场景,适合使用SoundPool

对于简单的播放,不需要复杂控制的播放,可以给使用AsyncPlayer,所有操作均在子线程不阻塞UI

播放大文件音乐,如WAV无损音频和PCM无压缩音频,可使用更底层的播放方式AudioTrack。它支持流式播放,可以读取(可来自本地和网络)音频流,却播放延迟较小。

ps:据我测试AudioTrack直接支持WAV和PCM,其他音频需要解码成PCM格式才能播放。(其他无损格式没有尝试,有兴趣可以使本文提供的例子测试一下)

.jet的音频比较少见(有的游戏中在使用),可使用专门的播放器JetPlayer播放

对于系统类声音的播放和操作,Ringtone更适合(主要是掌握好RingtoneManager)

android.media包中提供的播放音频的方式,远不止这些,本文只是参考api和其他大牛的博客做一些研究和记录,android.media种还有很多只是等着我们探索……

MediaPlay demo 接口api import androidx.annotation.RawRes; public interface IPlayerApi { /** * 加载媒体资源 * * @param musiUrl */ void loadMedia(String musiUrl, OnPrepareCompletedListener listener); /** * 加载元数据媒体资源 * * @param musicRawId */ void loadMedia(@RawRes int musicRawId, OnPrepareCompletedListener listener); /** * 释放资源 */ void release(); /** * 判断是否在播放 * * @return */ boolean isPlaying(); /** * 开始播放 */ void play(); /** * 重置 */ void reset(); /** * 暂停 */ void pause(); /** * 滑动到某个位置 */ void seekTo(int position); } 资源准备完成 public interface OnPrepareCompletedListener { void onComplete(); } 播放监听 public interface PlaybackInfoListener { void onTotalDuration(int duration);//总时长 void onPositionChanged(int position);//当前时长进度 void onStateChanged(int state);//记录当前的状态 void onPlayCompleted();//播放完成回调 } mediaplay适配 import android.content.res.AssetFileDescriptor; import android.media.MediaPlayer; import android.text.TextUtils; import android.util.Log; import androidx.annotation.RawRes; import com.tuya.smart.api.MicroContext; import java.io.IOException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class MediaPlayerAdpater implements IPlayerApi { public static int STATUS_PALYINGP = 0;//正在播放 public static int STATUS_STOP = 1;//暂停播放 public static int STATUS_RESET = 2;//重置 public static int STATUS_PLAY_COMPLETE = 3;//播放完成 public static int STATUS_PREPER_COMPLETE = 4;//媒体流装载完成 public static int STATUS_PREPER_ING = 5;//媒体流加载中 public static int STATUS_ERROR = -1;//错误 public int PLAYBACK_POSITION_REFRESH_INTERVAL_MS = 500; private final String TAG = "MediaPlayerHolder"; private MediaPlayer mMediaPlayer; /** * 开启线程 */ private ScheduledExecutorService mExecutor; private PlaybackInfoListener mPlaybackInfoListener; private Runnable mSeekbarPositionUpdateTask; // private String musiUrl;//音乐地址,可以是本地的音乐,可以是网络的音乐 public void setmPlaybackInfoListener(PlaybackInfoListener mPlaybackInfoListener) { this.mPlaybackInfoListener = mPlaybackInfoListener; } /** * 初始化MediaPlayer */ private void initializeMediaPlayer() { //注册,播放完成后的监听 mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { stopUpdatingCallbackWithPosition(true); if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onStateChanged(STATUS_PLAY_COMPLETE); mPlaybackInfoListener.onPlayCompleted(); } } }); //监听媒体流是否装载完成 mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { medisaPreparedCompled(); if (mOnPrepareCompletedListener != null) { mOnPrepareCompletedListener.onComplete(); } } }); // 监听媒体错误信息 mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onStateChanged(STATUS_ERROR); } Log.d(TAG, "OnError - Error code: " + what + " Extra code: " + extra); switch (what) { case -1004: Log.d(TAG, "MEDIA_ERROR_IO"); break; case -1007: Log.d(TAG, "MEDIA_ERROR_MALFORMED"); break; case 200: Log.d(TAG, "MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK"); break; case 100: Log.d(TAG, "MEDIA_ERROR_SERVER_DIED"); break; case -110: Log.d(TAG, "MEDIA_ERROR_TIMED_OUT"); break; case 1: Log.d(TAG, "MEDIA_ERROR_UNKNOWN"); break; case -1010: Log.d(TAG, "MEDIA_ERROR_UNSUPPORTED"); break; } switch (extra) { case 800: Log.d(TAG, "MEDIA_INFO_BAD_INTERLEAVING"); break; case 702: Log.d(TAG, "MEDIA_INFO_BUFFERING_END"); break; case 701: Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE"); break; case 802: Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE"); break; case 801: Log.d(TAG, "MEDIA_INFO_NOT_SEEKABLE"); break; case 1: Log.d(TAG, "MEDIA_INFO_UNKNOWN"); break; case 3: Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START"); break; case 700: Log.d(TAG, "MEDIA_INFO_VIDEO_TRACK_LAGGING"); break; } return false; } }); } private int mMusicRawId = 0; private String mMusicUrl = null; private OnPrepareCompletedListener mOnPrepareCompletedListener; /** * 加载媒体资源 * * @param musiUrl String:音乐地址,可以是本地的音乐,可以是网络的音乐 **/ @Override public void loadMedia(String musiUrl, OnPrepareCompletedListener listener) { if (TextUtils.isEmpty(musiUrl)) { Log.i(TAG, "地址为空"); return; } mOnPrepareCompletedListener = listener; mMusicUrl = musiUrl; if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onStateChanged(STATUS_PREPER_ING); } mMediaPlayer = new MediaPlayer(); initializeMediaPlayer(); try { //防止再次添加进来出现崩溃信息 mMediaPlayer.reset(); mMediaPlayer.setDataSource(musiUrl); mMediaPlayer.prepareAsync(); } catch (IOException e) { Log.e(TAG, e.getMessage().toString()); } } /** * 加载媒体资源 **/ @Override public void loadMedia(@RawRes int musicRawId, OnPrepareCompletedListener listener) { try { AssetFileDescriptor afd = MicroContext.getApplication().getResources().openRawResourceFd(musicRawId); if (afd == null) { Log.e(TAG, "afd == null"); return; } mOnPrepareCompletedListener = listener; if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onStateChanged(STATUS_PREPER_ING); } mMediaPlayer = new MediaPlayer(); initializeMediaPlayer(); //防止再次添加进来出现崩溃信息 mMediaPlayer.reset(); mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); mMediaPlayer.prepareAsync(); } catch (IOException e) { Log.e(TAG, e.getMessage().toString()); } } /** * 释放媒体资源 **/ @Override public void release() { if (mMediaPlayer != null) { stopUpdatingCallbackWithPosition(false); mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; mMusicUrl = null; mMusicRawId = 0; } } /** * 判断是否正在播放 **/ @Override public boolean isPlaying() { if (mMediaPlayer != null) { return mMediaPlayer.isPlaying(); } return false; } /** * 播放开始 **/ @Override public void play() { if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) { mMediaPlayer.start(); if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onStateChanged(STATUS_PALYINGP); } startUpdatingCallbackWithPosition(); } } /** * 开启线程,获取当前播放的进度 **/ private void startUpdatingCallbackWithPosition() { if (mExecutor == null) { mExecutor = Executors.newSingleThreadScheduledExecutor(); } if (mSeekbarPositionUpdateTask == null) { mSeekbarPositionUpdateTask = new Runnable() { @Override public void run() { updateProgressCallbackTask(); } }; } mExecutor.scheduleAtFixedRate( mSeekbarPositionUpdateTask, 0, PLAYBACK_POSITION_REFRESH_INTERVAL_MS, TimeUnit.MILLISECONDS ); } @Override public void reset() { if (mMediaPlayer != null) { if (mMusicUrl != null) { loadMedia(mMusicUrl, mOnPrepareCompletedListener); } else { loadMedia(mMusicRawId, mOnPrepareCompletedListener); } if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onStateChanged(STATUS_RESET); } stopUpdatingCallbackWithPosition(true); } } /** * 暂停 **/ @Override public void pause() { if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onStateChanged(STATUS_STOP); } stopUpdatingCallbackWithPosition(false); } } /** * 更新当前的进度 **/ private void updateProgressCallbackTask() { if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { try { int currentPosition = mMediaPlayer.getCurrentPosition(); if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onPositionChanged(currentPosition); } } catch (Exception e) { e.printStackTrace(); } } } /** * 加载完成回调:完成媒体流的装载 **/ private void medisaPreparedCompled() { int duration = mMediaPlayer.getDuration();//获取总时长 if (mPlaybackInfoListener != null) { mPlaybackInfoListener.onTotalDuration(duration); mPlaybackInfoListener.onPositionChanged(0); mPlaybackInfoListener.onStateChanged(STATUS_PREPER_COMPLETE); } } /** * 滑动播放到某个位置 **/ @Override public void seekTo(int position) { if (mMediaPlayer != null) { mMediaPlayer.seekTo(position); } } /** * 播放完成回调监听 **/ private void stopUpdatingCallbackWithPosition(boolean resetUIPlaybackPosition) { if (mExecutor != null) { mExecutor.shutdownNow(); mExecutor = null; mSeekbarPositionUpdateTask = null; if (resetUIPlaybackPosition && mPlaybackInfoListener != null) { mPlaybackInfoListener.onPositionChanged(0); } } } }

参考:

Android中播放音乐的几种方式Android多媒体开发(5)————利用Android AudioTrack播放mp3文件Android音频系统之AudioTrack(一)Android SoundPool 使用和封装


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有