zoukankan      html  css  js  c++  java
  • Android 音频播放速率调整实现

      最近接触到的一个项目, 有音频播放、切换播放速率和拖动进度到某处播放的需求 ,由于之前只是见过并没有尝试过切换播放速率 , 于是开始调研并最终实现,下面简单记录一下这次的调研过程。

    • MediaPlayer

    播放音频最先想到的就是MediaPlayer这个Android提供的原生API了,在Android 6.0+(23+)MediaPlayer可以通过setSpeed来改变播放速率

    在代码中,我们需要:

    // 设置音乐播放速度 
    public static void changeplayerSpeed(float speed) { 
        if (mPlayer == null)  {
            return; 
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
            // API 23 (6.0)以上 ,通过设置Speed改变音乐的播放速率
            if (mPlayer.isPlaying()) {
                // 判断是否正在播放,未播放时,要在设置Speed后,暂停音乐播放
                mPlayer.setPlaybackParams(mPlayer.getPlaybackParams().setSpeed(speed)); 
            } else {
                mPlayer.setPlaybackParams(mPlayer.getPlaybackParams().setSpeed(speed)); 
                mPlayer.pause(); 
            } 
        } else {
            // 在Android6.0以前,需要另想办法处理,后续查到好的方法再补充
        }
    }

    实际实现过程中 ,我发现手上的测试机Honor V9执行该操作后 ,播放静默了 ,不仅没有实现播放速率的切换,播放也不能恢复。无奈,只好另寻他法。

    • PLMediaPlayer 

    PLDroidPlayer是七牛SDK提供的一套API, PLMediaPlayer实现了一个媒体播放器的各种基础功能和接口,与 Android 官方的 MediaPlayer 的设计基本保持一致。

    关键代码就一行

        private PLOnPreparedListener mOnPreparedListener = new PLOnPreparedListener() {
            @Override
            public void onPrepared(int preparedTime) {
                Log.i(TAG, "On Prepared !");
                mMediaPlayer.start();
           //设置播放速率为2x mMediaPlayer.setPlaySpeed(
    2.0f); mIsStopped = false; } };

     实际实现过程中 ,播放速率切换正常,但seekTo操作大概率失效,于是去github上查探究竟,发现仍存在该问题的ISSUE,遂放弃。

    • ijkPlayer

    ijkplayer是b站基于ffplay的轻量级Android/iOS视频播放器,实现了跨平台的功能,API易于集成;编译配置可裁剪,方便控制安装包大小。

    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", 1);
    ijkMediaPlayer.setSpeed(2.0f);

    api和用法类似mediaplayer,关键代码也是只有一行。

    实际实现过程中 ,seekTo正常,播放速率切换也正常(只是在切换到慢速0.5x的时候存在重音的情况),但是播放不了https开头url的音频文件,搜索了一下需要自己编译ijkplayer源码以支持https,遂放弃。

    • ExoPlayer

     最终选择的是google的exoPlayer来实现,api类似MediaPlayer,但也有些差异,下面贴出关键播放控制部分的代码。

    package com.weex.app.media;
    
    import android.content.Context;
    import android.net.Uri;
    
    import com.google.android.exoplayer2.ExoPlayer;
    import com.google.android.exoplayer2.ExoPlayerFactory;
    import com.google.android.exoplayer2.PlaybackParameters;
    import com.google.android.exoplayer2.Player;
    import com.google.android.exoplayer2.SimpleExoPlayer;
    import com.google.android.exoplayer2.source.ExtractorMediaSource;
    import com.google.android.exoplayer2.source.MediaSource;
    import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
    import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
    import com.google.android.exoplayer2.trackselection.TrackSelection;
    import com.google.android.exoplayer2.trackselection.TrackSelector;
    import com.google.android.exoplayer2.upstream.BandwidthMeter;
    import com.google.android.exoplayer2.upstream.DataSource;
    import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
    import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
    import com.google.android.exoplayer2.util.Util;
    
    import java.io.File;
    
    public class AudioPlayerManager {
    
        private static final String TAG = "AudioPlayerManager";
        public static Float[] speedArray = new Float[]{1.0f, 1.25f, 1.75f, 0.5f, 0.75f};
        private static AudioPlayerManager instance;
        private Context context;
        private SimpleExoPlayer mediaPlayer;
        private DataSource.Factory dataSourceFactory;
    
        private AudioPlayerManager(Context context) {
            this.context = context;
            createPlayer();
        }
    
        public static AudioPlayerManager getInstance(Context context) {
            synchronized (AudioPlayerManager.class) {
                if (instance == null) {
                    instance = new AudioPlayerManager(context);
                }
            }
    
            return instance;
        }
    
        public ExoPlayer getMediaPlayer() {
            return mediaPlayer;
        }
      //设置播放url
        public void setAudioUrl(String audioUrl) {
            try {
                //这是一个代表将要被播放的媒体的MediaSource
                MediaSource mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory)
                        .createMediaSource(Uri.parse(audioUrl));
                mediaPlayer.prepare(mediaSource);
                mediaPlayer.setPlayWhenReady(false);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
      //设置播放file
        public void setAudioFile(File file) {
            try {
                //这是一个代表将要被播放的媒体的MediaSource
                MediaSource mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory)
                        .createMediaSource(Uri.fromFile(file));
                mediaPlayer.prepare(mediaSource);
                mediaPlayer.setPlayWhenReady(false);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
      //开始播放
        public void start() {
            mediaPlayer.setPlayWhenReady(true);
        }
      //判断是否是播放状态
        public boolean isPlaying() {
            int playbackState = mediaPlayer.getPlaybackState();
            if (playbackState == SimpleExoPlayer.STATE_READY && mediaPlayer.getPlayWhenReady()) {
                return true;
            }
            return false;
        }
      //播放,带回调事件
        public void playWithCompletionListener(String url, Player.EventListener listener) {
            if (listener != null) {
                mediaPlayer.addListener(listener);
            }
            if (url.startsWith("http")) {
                setAudioUrl(url);
            } else {
                setAudioFile(new File(url));
            }
            mediaPlayer.setPlayWhenReady(true);
        }
      //播放or暂停
        public void playOrPause() {
            if (isPlaying()) {
                mediaPlayer.setPlayWhenReady(false);
            } else {
                mediaPlayer.setPlayWhenReady(true);
            }
        }
      //切换播放速率
        public void switchSpeed(int speedIndex) {
            // API 23 (6.0)以上 ,通过设置Speed改变音乐的播放速率
            if (isPlaying()) {
                // 判断是否正在播放,未播放时,要在设置Speed后,暂停音乐播放
                getMediaPlayer().setPlaybackParameters(new PlaybackParameters(speedArray[speedIndex]));
            } else {
                getMediaPlayer().setPlaybackParameters(new PlaybackParameters(speedArray[speedIndex]));
                getMediaPlayer().setPlayWhenReady(false);
            }
        }
      //停止播放
        public void stop(boolean reset) {
            if (mediaPlayer != null) {
                mediaPlayer.stop(reset);
            }
        }
      //释放资源
        public void release() {
            if (mediaPlayer != null) {
                mediaPlayer.release();
            }
        }
    
        //创建一个新的player
        private void createPlayer() {
            // 创建带宽
            BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
            // 创建轨道选择工厂
            TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
            // 创建轨道选择器实例
            TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
            //step2.创建播放器
            mediaPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
            //创建一个DataSource对象,通过它来下载多媒体数据
            dataSourceFactory = new DefaultDataSourceFactory(context,
                    Util.getUserAgent(context, "loader"));
        }
    
    }

     实际自测过程中,表现正常,而且切换播放速率时,没有重(chong)音的情况,但没有在6.0以下的设备上测试过。

  • 相关阅读:
    古代汉语:含义“死”的归类
    Inesa 路由器登录信息
    调试第三方源码
    暑假作业日总结
    暑假作业日总结
    暑假作业日总结
    暑假作业日总结
    暑假作业日总结
    暑假作业:《大道至简》读后感
    暑假作业日总结
  • 原文地址:https://www.cnblogs.com/fuyaozhishang/p/11098596.html
Copyright © 2011-2022 走看看