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以下的設備上測試過。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM