Browse Source

增加云教练评测调速

Pq 8 months ago
parent
commit
fa281052e6

+ 3 - 0
accompany/build.gradle

@@ -73,4 +73,7 @@ dependencies {
     //ARouter
     implementation "com.alibaba:arouter-api:$rootProject.ext.android.arouter_api_version"
     kapt "com.alibaba:arouter-compiler:$rootProject.ext.android.arouter_api_version"
+
+    //ijkPlayer
+    api 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
 }

BIN
accompany/libs/arm64-v8a/libijkffmpeg.so


BIN
accompany/libs/arm64-v8a/libijkplayer.so


BIN
accompany/libs/arm64-v8a/libijksdl.so


BIN
accompany/libs/armeabi-v7a/libijkffmpeg.so


BIN
accompany/libs/armeabi-v7a/libijkplayer.so


BIN
accompany/libs/armeabi-v7a/libijksdl.so


+ 20 - 0
accompany/src/main/java/com/daya/orchestra/accompany/common/Constants.java

@@ -0,0 +1,20 @@
+package com.daya.orchestra.accompany.common;
+
+/**
+ * Author by pq, Date on 2024/1/9.
+ */
+public class Constants {
+    public static boolean DEBUG = true;
+    public static String HEADSET_PLUE_TAG = "";
+    public final static String WEB_URL = "web_url";
+    public final static String PARAMS_ISHIDETITLE = "isHideTitle";
+    public final static String PARAMS_ISOPENLIGHT = "isOpenLight";
+    public final static String PARAMS_C_ORIENTATION = "c_orientation";
+    public final static String PARAMS_ORIENTATION = "orientation";
+    public final static String RECORD_SUCCESS = "record_success";
+    public final static String RECORD_ERROR = "record_error";
+    public final static int WEBSOCKET_HEARTBEAT_TIME = 30000;
+    public final static float MAX_PLAY_SPEED = 5.0f;
+    public final static float MIN_PLAY_SPEED = 0.3f;
+    public final static float DEFAULT_PLAY_SPEED = 1.0f;
+}

+ 23 - 15
accompany/src/main/java/com/daya/orchestra/accompany/helper/AccompanyPlayHelper.java

@@ -20,7 +20,9 @@ import com.cooleshow.base.utils.MyFileUtils;
 import com.cooleshow.base.utils.ToastUtil;
 import com.cooleshow.base.websocket.JWebSocketClient;
 import com.cooleshow.usercenter.helper.UserHelper;
+import com.daya.orchestra.accompany.common.Constants;
 import com.daya.orchestra.accompany.player.CustomPlayer;
+import com.daya.orchestra.accompany.presenter.CustomIJKPlayer;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -35,11 +37,12 @@ import io.reactivex.rxjava3.core.ObservableOnSubscribe;
 import io.reactivex.rxjava3.core.Observer;
 import io.reactivex.rxjava3.disposables.Disposable;
 import io.reactivex.rxjava3.schedulers.Schedulers;
+import tv.danmaku.ijk.media.player.IMediaPlayer;
 
 /**
  * Author by pq, Date on 2023/8/4.
  */
-public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
+public class AccompanyPlayHelper implements IMediaPlayer.OnCompletionListener {
     public static final String TAG = "AccPlayHelper";
 
     public static long realPlayStartTime = -1;
@@ -52,7 +55,7 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
     public static final String BLANK_DEVICE_DELAY_CACHE_KEY = "delay_cache";
     public static final String DELAY_FOR_CURRENT_CACHE_KEY = "delayForCurrent";
     private Recorder wavRecorder;
-    private CustomPlayer player;
+    private CustomIJKPlayer player;
     private long startPlayTime = 0;
     private boolean isTag = true;
 
@@ -71,8 +74,8 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
             if (player == null) {
                 return;
             }
-            int cu = player.getCu();
-            int duration = player.getT();
+            long cu = player.getCu();
+            long duration = player.getT();
             if (cu > 500) {
                 if (isTag) {
                     LOG.i(TAG, "cu:" + cu);
@@ -92,10 +95,10 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
     private Runnable mRunnable2 = new Runnable() {
         @Override
         public void run() {
-            CustomPlayer player = getPlayer();
-            int cu = player.getCu();
-            int duration = player.getT();
-            int exceptTargetPos = player.getExceptTargetPos(cu);
+            CustomIJKPlayer player = getPlayer();
+            long cu = player.getCu();
+            long duration = player.getT();
+            long exceptTargetPos = player.getExceptTargetPos(cu);
             if (exceptTargetPos > 1000) {
                 if (isTag) {
                     LOG.i(TAG, "第二段cu:" + exceptTargetPos);
@@ -340,7 +343,7 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
         loopHandler.postDelayed(mTuneRunnable, 10);
         getPlayer().stop();
         getPlayer().setPrepareSeekPosition(-1);
-        getPlayer().play(false, tuneSrc);
+        getPlayer().play(false, Constants.DEFAULT_PLAY_SPEED, tuneSrc);
 //        String fileName;
 //        LOG.i("pq", "toPlayTuneMusic" + delayCheckResults.size());
 //        if (delayCheckResults.size() == 0) {
@@ -426,7 +429,7 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
 
     }
 
-    private void sendPlayProgressMessage(int cu, int duration) {
+    private void sendPlayProgressMessage(long cu, long duration) {
         JSONObject jsonObject = new JSONObject();
         JSONObject contentObject = new JSONObject();
         try {
@@ -477,9 +480,9 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
         wavRecorder = null;
     }
 
-    private CustomPlayer getPlayer() {
+    private CustomIJKPlayer getPlayer() {
         if (player == null) {
-            player = new CustomPlayer();
+            player = new CustomIJKPlayer();
             player.setOnCompletionListener(this);
         }
         return player;
@@ -522,6 +525,10 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
     }
 
     public void toPlay2(long startTime, int firstNoteTime, boolean isMute) {
+        toPlay2(startTime, firstNoteTime, Constants.DEFAULT_PLAY_SPEED, isMute);
+    }
+
+    public void toPlay2(long startTime, int firstNoteTime, float speed, boolean isMute) {
         if (TextUtils.isEmpty(musicSrc)) {
             return;
         }
@@ -529,16 +536,17 @@ public class AccompanyPlayHelper implements MediaPlayer.OnCompletionListener {
         UserHelper.setCustomCache(DELAY_FOR_CURRENT_CACHE_KEY, 0);
         isTag = true;
         startPlayTime = startTime;
-        Log.i("pq", "评测曲子startTime:" + startPlayTime);
+        LOG.i("pq", "评测曲子startTime:" + startPlayTime);
         loopHandler.removeCallbacksAndMessages(null);
         loopHandler.postDelayed(mRunnable2, 10);
         getPlayer().stop();
         getPlayer().setPrepareSeekPosition(firstNoteTime);
-        getPlayer().play(isMute, musicSrc);
+        getPlayer().play(isMute, speed, musicSrc);
     }
 
+
     @Override
-    public void onCompletion(MediaPlayer mp) {
+    public void onCompletion(IMediaPlayer iMediaPlayer) {
         LOG.i(TAG, "play onCompletion");
         if (loopHandler != null) {
             loopHandler.removeCallbacks(mRunnable2);

+ 226 - 0
accompany/src/main/java/com/daya/orchestra/accompany/presenter/CustomIJKPlayer.java

@@ -0,0 +1,226 @@
+package com.daya.orchestra.accompany.presenter;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import com.cooleshow.base.utils.LOG;
+import com.daya.orchestra.accompany.common.Constants;
+
+import java.io.IOException;
+
+import tv.danmaku.ijk.media.player.IMediaPlayer;
+import tv.danmaku.ijk.media.player.IjkMediaPlayer;
+
+/**
+ * Author by pq, Date on 2023/5/11.
+ */
+public class CustomIJKPlayer implements IjkMediaPlayer.OnErrorListener, IjkMediaPlayer.OnCompletionListener, IjkMediaPlayer.OnPreparedListener {
+    public static final String TAG = "CustomPlayer";
+    private Context mContext;
+    IjkMediaPlayer mPlayer;
+    private boolean hasPrepared;
+    private boolean isStoped = false;
+
+    private boolean isNeedMute = false;
+
+    private int prepareSeekPosition = -1;//此字段用于选段播放
+
+    public CustomIJKPlayer() {
+        initPlayer();
+    }
+
+    private void initPlayer() {
+        if (null == mPlayer) {
+            mPlayer = new IjkMediaPlayer();
+            mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            mPlayer.setOnErrorListener(this);
+            mPlayer.setOnCompletionListener(this);
+            mPlayer.setOnPreparedListener(this);
+        }
+    }
+
+    public void setOnCompletionListener(IjkMediaPlayer.OnCompletionListener listener) {
+        if (mPlayer != null) {
+            mPlayer.setOnCompletionListener(listener);
+        }
+    }
+
+    public void play(Context context, Uri dataSource) {
+        hasPrepared = false; // 开始播放前讲Flag置为不可操作
+        isStoped = false;
+        initPlayer(); // 如果是第一次播放/player已经释放了,就会重新创建、初始化
+        try {
+            mPlayer.reset();
+            mPlayer.setDataSource(context, dataSource); // 设置曲目资源
+            mPlayer.prepareAsync(); // 异步的准备方法
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void play(boolean isMute, float speed,String path) {
+        hasPrepared = false; // 开始播放前讲Flag置为不可操作
+        isStoped = false; //
+        this.isNeedMute = isMute;
+        initPlayer(); // 如果是第一次播放/player已经释放了,就会重新创建、初始化
+        try {
+            mPlayer.reset();
+            initOptions(speed);
+            mPlayer.setDataSource(path); // 设置曲目资源
+            mPlayer.prepareAsync(); // 异步的准备方法
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void initOptions(float speed) {
+        if(speed != Constants.DEFAULT_PLAY_SPEED){
+            mPlayer.setSpeed(speed);
+            mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", 1);
+        }
+        mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1);
+        // 设置缓存策略
+        mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 1);
+        mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 5);
+        mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", 4);
+        //硬件加速
+        mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
+        mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
+        // 调整同步设置
+        mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "sync", "audio");
+    }
+
+    public int getPrepareSeekPosition() {
+        return prepareSeekPosition;
+    }
+
+    public long getExceptTargetPos(long cu) {
+        //用于选段评测流程 如果有选段快进则需要 按照快进开播播放的位置取
+        long targetPos = getPrepareSeekPosition() != -1 ? cu - getPrepareSeekPosition() : cu;
+        return targetPos;
+    }
+
+    public void setPrepareSeekPosition(int prepareSeekPosition) {
+        this.prepareSeekPosition = prepareSeekPosition;
+    }
+
+    public long getCu() {
+        if (mPlayer != null) {
+            long currentPosition = mPlayer.getCurrentPosition();
+            return currentPosition;
+        }
+        return -1;
+    }
+
+
+    public long getT() {
+        if (mPlayer != null) {
+            long duration = mPlayer.getDuration();
+            return duration;
+        }
+        return -1;
+    }
+
+    public void start() {
+        if (isStoped) {
+            return;
+        }
+        // release()会释放player、将player置空,所以这里需要判断一下
+        if (null != mPlayer && hasPrepared) {
+            mPlayer.start();
+            setVolume(isNeedMute ? 0f : 1f);
+            if (prepareSeekPosition > 0) {
+                seekTo(prepareSeekPosition);
+            }
+        }
+    }
+
+    public void setVolume(float volume) {
+        if (mPlayer != null) {
+            LOG.i(TAG,"setVolume:" + volume + "hasPrepared:" + hasPrepared);
+            mPlayer.setVolume(volume, volume);
+        }
+    }
+
+    public void pause() {
+        if (null != mPlayer && hasPrepared) {
+            mPlayer.pause();
+        }
+    }
+
+    public void seekTo(int position) {
+        if (null != mPlayer && hasPrepared) {
+            mPlayer.seekTo(position);
+        }
+    }
+
+    // 对于播放视频来说,通过设置SurfaceHolder来设置显示Surface。这个方法不需要判断状态、也不会改变player状态
+    public void setDisplay(SurfaceHolder holder) {
+        if (null != mPlayer) {
+            mPlayer.setDisplay(holder);
+        }
+    }
+
+
+    public void stop() {
+        if (mPlayer == null) {
+            return;
+        }
+        prepareSeekPosition = -1;
+        isStoped = true;
+        hasPrepared = false;
+        Log.i(TAG, "player to stop:" + hasPrepared + "-thread:" + Thread.currentThread().getName());
+        mPlayer.stop();
+    }
+
+    @Override
+    public void onCompletion(IMediaPlayer iMediaPlayer) {
+        hasPrepared = false;
+        LOG.i(TAG, "onCompletion");
+        // 通知调用处,调用play()方法进行下一个曲目的播放
+    }
+
+    @Override
+    public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {
+        hasPrepared = false;
+        return true;
+    }
+
+    @Override
+    public void onPrepared(IMediaPlayer iMediaPlayer) {
+        hasPrepared = true; // 准备完成后回调到这里
+        start();
+    }
+
+    public void setSpeed(float speed) {
+        Log.i(TAG, "setSpeed:" + speed);
+        try {
+            if (mPlayer != null) {
+                if (speed > Constants.MAX_PLAY_SPEED) {
+                    speed = Constants.MAX_PLAY_SPEED;
+                }
+                if (speed < Constants.MIN_PLAY_SPEED) {
+                    speed = Constants.MIN_PLAY_SPEED;
+                }
+                mPlayer.setSpeed(speed);
+                mPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", 1);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    public void release() {
+        hasPrepared = false;
+        isStoped = true;
+        mPlayer.stop();
+        mPlayer.release();
+        mPlayer = null;
+    }
+
+
+}

+ 14 - 1
accompany/src/main/java/com/daya/orchestra/accompany/web/AccompanyFragment.java

@@ -747,7 +747,7 @@ public class AccompanyFragment extends BaseMVPFragment<FragmentAccompanyV2Bindin
                                 long bufferDuration = wavRecorder != null ? (long) wavRecorder.getBufferDuration() : 0;
                                 long time = System.currentTimeMillis();
                                 long result = time - bufferDuration;
-                                mPlayHelper.toPlay2(result, getFirstNoteTime(message), isMuteMode(message));
+                                mPlayHelper.toPlay2(result, getFirstNoteTime(message), getPlaySpeed(message),isMuteMode(message));
                             } else if ("1".equals(recorder)) {
 //                                onSendMessage(message.toString());
                             } else {
@@ -807,6 +807,19 @@ public class AccompanyFragment extends BaseMVPFragment<FragmentAccompanyV2Bindin
         return 0;
     }
 
+    private float getPlaySpeed(JSONObject jsonObject) {
+        if (jsonObject == null) {
+            return 0;
+        }
+        JSONObject contentJson = jsonObject.optJSONObject("content");
+        //获取选段位置
+        if (contentJson != null) {
+            float firstNoteTime = (float) contentJson.optDouble("speedRate", com.daya.orchestra.accompany.common.Constants.DEFAULT_PLAY_SPEED);
+            return firstNoteTime;
+        }
+        return com.daya.orchestra.accompany.common.Constants.DEFAULT_PLAY_SPEED;
+    }
+
     private boolean isMuteMode(JSONObject jsonObject) {
         if (jsonObject == null) {
             return false;