Browse Source

网络教室添加课件播放逻辑

Pq 2 years ago
parent
commit
8199787806

+ 194 - 0
live_teaching/src/main/java/com/daya/live_teaching/rtc/RtcAudioMixerControl.java

@@ -0,0 +1,194 @@
+package com.daya.live_teaching.rtc;
+
+import android.util.Log;
+
+import cn.rongcloud.rtc.api.RCRTCAudioMixer;
+import cn.rongcloud.rtc.api.callback.RCRTCAudioMixingStateChangeListener;
+
+/**
+ * Author by pq, Date on 2022/11/16.
+ */
+public class RtcAudioMixerControl extends RCRTCAudioMixingStateChangeListener {
+    private OnEventListener mEventListener;
+    private String currentUrl ="";
+
+    public RtcAudioMixerControl(OnEventListener onEventListener) {
+        mEventListener = onEventListener;
+        setAudioMixingStateChangeListener();
+    }
+
+    /**
+     * 开始播放
+     *
+     * @param fileUrl
+     */
+    public void startMix(String fileUrl) {
+        Log.i("pq", "fileUrl:" + fileUrl);
+        this.currentUrl=fileUrl;
+        RCRTCAudioMixer.getInstance().startMix(fileUrl, RCRTCAudioMixer.Mode.MIX, true, -1);
+    }
+
+    /**
+     * 调节观众端音量
+     *
+     * @param vol
+     */
+    public void updateOtherUserVolume(int vol) {
+        // 调节混音音量(修改的是对端听到的声音音量)
+        RCRTCAudioMixer.getInstance().setMixingVolume(vol);
+    }
+
+    /**
+     * 调节主播端音量
+     *
+     * @param vol
+     */
+    public void updateCurrentUserVolume(int vol) {
+        // 调节本地播放音量(修改的是本端听到的声音音量)
+        RCRTCAudioMixer.getInstance().setPlaybackVolume(vol);
+    }
+
+    /**
+     * 获取总时长
+     *
+     * @return
+     */
+    public int getDurationMillis() {
+        // 获取混音文件播放总时长(ms),方法一
+        return RCRTCAudioMixer.getInstance().getDurationMillis();
+    }
+
+    /**
+     * 获取指定文件总时长
+     *
+     * @return
+     */
+    public int getTargetFileDurationMillis(String path) {
+        // 获取混音文件播放总时长(ms),方法二
+        return RCRTCAudioMixer.getInstance().getDurationMillis(path);
+    }
+
+    /**
+     * 获取当前播放进度
+     *
+     * @return
+     */
+    public float getCurrentPosition() {
+        // 获取混音进度,例如 0.2 表示播放了 20%
+        return RCRTCAudioMixer.getInstance().getCurrentPosition();
+    }
+
+    /**
+     * 快进至
+     *
+     * @param position
+     */
+    public void seekTo(float position) {
+        // 调节混音进度,例如 0.2 表示调节至 20% 处开始播放
+        RCRTCAudioMixer.getInstance().seekTo(position);
+    }
+
+    /**
+     * 暂停播放
+     */
+    public void pause() {
+        // 暂停混音
+        RCRTCAudioMixer.getInstance().pause();
+    }
+
+    /**
+     * 恢复播放
+     */
+    public void resume() {
+        // 暂停混音
+        RCRTCAudioMixer.getInstance().resume();
+    }
+
+    /**
+     * 停止播放
+     */
+    public void stop() {
+        // 停止混音
+        RCRTCAudioMixer.getInstance().stop();
+    }
+
+    /**
+     * 设置播放状态listener
+     *
+     * @param
+     */
+    public void setAudioMixingStateChangeListener() {
+        RCRTCAudioMixer.getInstance().setAudioMixingStateChangeListener(this);
+    }
+
+    @Override
+    public void onStateChanged(RCRTCAudioMixer.MixingState state, RCRTCAudioMixer.MixingStateReason reason) {
+        Log.i("pq", "state:" + state);
+        Log.i("pq", "reason:" + reason);
+        if (state == RCRTCAudioMixer.MixingState.STOPPED) {
+            // 混音完成,可能的原因有:
+            if (reason == RCRTCAudioMixer.MixingStateReason.ALL_LOOPS_COMPLETED) {
+                // 调用startMix方法时,传入的loopCount > 0,并且loopCount次数的混音已经完成
+            } else if (reason == RCRTCAudioMixer.MixingStateReason.ONE_LOOP_COMPLETED) {
+                // 调用startMix方法时,传入的loopCount < 0(无限循环)或 > 1,混音完成一次。接下来会继续自动开始下一次混音。
+            } else if (reason == RCRTCAudioMixer.MixingStateReason.STOPPED_BY_USER) {
+                // 调用stopMix方法停止混音
+                if (mEventListener != null) {
+                    mEventListener.onStop();
+                }
+            }
+        } else if (state == RCRTCAudioMixer.MixingState.PLAY) {
+            // 开始混音,可能的原因有:
+            if (reason == RCRTCAudioMixer.MixingStateReason.STARTED_BY_USER) {
+                // 调用了 startMix 方法开始混音
+                if (mEventListener != null) {
+//                    int durationMillis = getDurationMillis();
+                    mEventListener.onStartPlay();
+                }
+            } else if (reason == RCRTCAudioMixer.MixingStateReason.START_NEW_LOOP) {
+                // 调用了 startMix 且传入的 loopCount < 0(无限循环)或 > 1 时,自动开始下一次混音。
+            } else if (reason == RCRTCAudioMixer.MixingStateReason.RESUMED_BY_USER) {
+                // 调用了 resume方法继续开始混音
+                if (mEventListener != null) {
+                    mEventListener.onResumePlay();
+                }
+            }
+        } else if (state == RCRTCAudioMixer.MixingState.PAUSED) {
+            // 暂停混音,reason 为 MixingStateReason.PAUSED_BY_USER
+            if (mEventListener != null) {
+                mEventListener.onPausePlay();
+            }
+        } else if (state == RCRTCAudioMixer.MixingState.ERROR) {
+
+        }
+    }
+
+
+    /**
+     * Added from 5.1.4
+     * 混音播放进度,默认 200 毫秒回调一次
+     *
+     * @param progress 播放进度 [0,1]
+     */
+    @Override
+    public void onReportPlayingProgress(float progress) {
+        if (mEventListener != null) {
+            mEventListener.onProgress(progress);
+        }
+//        Log.i("pq", "onReportPlayingProgress:" + progress);
+//        int durationMillis = getDurationMillis();
+//        Log.i("pq", "durationMillis:" + durationMillis);
+    }
+
+    public interface OnEventListener {
+        void onProgress(float progress);
+
+        void onStartPlay();
+
+        void onPausePlay();
+
+        void onResumePlay();
+
+        void onStop();
+    }
+}

+ 13 - 4
live_teaching/src/main/java/com/daya/live_teaching/ui/LiveActivity.java

@@ -11,7 +11,6 @@ import android.text.TextUtils;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.Window;
 import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
@@ -35,7 +34,6 @@ import com.cooleshow.base.utils.LogUtils;
 import com.cooleshow.base.utils.SizeUtils;
 import com.cooleshow.base.utils.ToastUtil;
 import com.cooleshow.base.utils.Utils;
-import com.cooleshow.base.utils.helper.QMUIStatusBarHelper;
 import com.daya.live_teaching.R;
 import com.daya.live_teaching.callback.CoursewareDataResultCallBack;
 import com.daya.live_teaching.common.ShowToastObserver;
@@ -717,8 +715,10 @@ public class LiveActivity extends BaseActivity<ActivityLiveBinding> {
                 }
 
                 @Override
-                public void onPlayCourseware(String coursewareUrl) {
-
+                public void onPlayCourseware(String coursewareName, String coursewareUrl) {
+                    if (!TextUtils.isEmpty(coursewareUrl)) {
+                        startMix(coursewareName,coursewareUrl);
+                    }
                 }
             });
         }
@@ -728,6 +728,12 @@ public class LiveActivity extends BaseActivity<ActivityLiveBinding> {
         }
     }
 
+    private void startMix(String coursewareName,String fileUrl) {
+        viewBinding.viewCourseware.setVisibility(View.VISIBLE);
+        viewBinding.viewCourseware.setName(coursewareName);
+        viewBinding.viewCourseware.start(fileUrl);
+    }
+
     public void initClassViewModel(Intent intent) {
         isRefreshClassViewModel = true;
 
@@ -1398,6 +1404,9 @@ public class LiveActivity extends BaseActivity<ActivityLiveBinding> {
                 onStopHandler = null;
                 onStoprunnable = null;
             }
+            if (viewBinding.viewCourseware != null) {
+                viewBinding.viewCourseware.release();
+            }
             RCRTCEngine.getInstance().getDefaultAudioStream().changeAudioScenario(RCRTCParamsType.AudioScenario.DEFAULT, () -> {
                 RCRTCEngine.getInstance().init(getApplicationContext(), RCRTCConfig.Builder.create().enableStereo(true).build());
             });

+ 215 - 1
live_teaching/src/main/java/com/daya/live_teaching/widget/CourseWarePlayView.java

@@ -1,19 +1,71 @@
 package com.daya.live_teaching.widget;
 
 import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
 
+import com.cooleshow.base.utils.DateUtil;
 import com.daya.live_teaching.R;
+import com.daya.live_teaching.rtc.RtcAudioMixerControl;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.appcompat.widget.AppCompatSeekBar;
+import androidx.constraintlayout.widget.Group;
 
 /**
  * Author by pq, Date on 2022/11/15.
  */
-public class CourseWarePlayView extends FrameLayout {
+public class CourseWarePlayView extends FrameLayout implements View.OnClickListener {
+    public static final int PLAY_STATUS_LOADING = 0;//加载中
+    public static final int PLAY_STATUS_PLAYING = 1;//播放中
+    public static final int PLAY_STATUS_PAUSE = 2;//暂停
+    public static final int PLAY_STATUS_STOP = 4;//停止播放
+    public static final int PLAY_STATUS_FAIL = 3;//播放失败
+    public static final int MAX_SEEKBAR_PROGRESS = 100;//进度条最大值
+
+
+    public static final int UPDATE_PROGRESS_TYPE = 1001;
+    public static final int UPDATE_PLAY_STATUS = 1002;
+
+    private TextView mTvTitle;
+    private Group mGroupPlayInfo;
+    private ImageView mIvStatusIcon;
+    private TextView mTvProgress;
+    private TextView mTvStatusText;
+    private AppCompatSeekBar mSeekbar;
+    private ImageView mIvPlay;
+    private int coursewareTotalTime = 0;
+    private int playStatus = PLAY_STATUS_LOADING;
+    private RtcAudioMixerControl mRtcAudioMixerControl;
+    private Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(@NonNull Message msg) {
+            super.handleMessage(msg);
+            if (msg.what == UPDATE_PROGRESS_TYPE) {
+                float progress = (float) msg.obj;
+                setPlayProgress(progress);
+                return;
+            }
+
+            if (msg.what == UPDATE_PLAY_STATUS) {
+                int playStatus = (int) msg.obj;
+                setPlayStatus(playStatus);
+                return;
+            }
+        }
+    };
+
+
     public CourseWarePlayView(@NonNull Context context) {
         this(context, null);
     }
@@ -29,6 +81,168 @@ public class CourseWarePlayView extends FrameLayout {
 
     private void init() {
         LayoutInflater.from(getContext()).inflate(R.layout.view_course_ware_play_layout, this);
+        mTvTitle = findViewById(R.id.tv_title);
+        mGroupPlayInfo = findViewById(R.id.group_play_info);
+        mIvPlay = findViewById(R.id.iv_play);
+        mSeekbar = findViewById(R.id.seekbar);
+        mTvProgress = findViewById(R.id.tv_progress);
+        mTvStatusText = findViewById(R.id.tv_status_text);
+        mIvStatusIcon = findViewById(R.id.iv_status_icon);
+        mIvPlay.setOnClickListener(this);
+        mIvStatusIcon.setOnClickListener(this);
+    }
+
+    public void setName(String name) {
+        if (mTvTitle != null) {
+            mTvTitle.setText(name);
+        }
+    }
+
+    public void setTotalProgress(int totalTime) {
+        this.coursewareTotalTime = totalTime;
+        Log.i("pq", "total Time:" + coursewareTotalTime);
+        String s = DateUtil.dateFormatmm_ss(totalTime);
+        mTvProgress.setText("00:00/" + s);
+    }
+
+    /**
+     * Added from 5.1.4
+     * 混音播放进度,默认 200 毫秒回调一次
+     *
+     * @param progress 播放进度 [0,1]
+     */
+    public void setPlayProgress(float progress) {
+        Log.i("pq", "progress:" + progress);
+        int currentProgress = (int) (MAX_SEEKBAR_PROGRESS * progress);
+        Log.i("pq", "currentProgress:" + currentProgress);
+        if (mSeekbar != null) {
+            mSeekbar.setProgress(currentProgress);
+        }
+    }
+
+    public void setPlayStatus(int playStatus) {
+        this.playStatus = playStatus;
+        if (playStatus == PLAY_STATUS_LOADING) {
+            mGroupPlayInfo.setVisibility(View.GONE);
+            mIvStatusIcon.setVisibility(View.GONE);
+            mTvStatusText.setText("正在加载...");
+            return;
+        }
+
+        if (playStatus == PLAY_STATUS_FAIL) {
+            //加载失败
+            mGroupPlayInfo.setVisibility(View.GONE);
+            mIvStatusIcon.setVisibility(View.VISIBLE);
+            mIvStatusIcon.setImageResource(R.drawable.icon_play_courseware_reload);
+            mTvStatusText.setText("重新加载");
+            return;
+        }
+
+        if (playStatus == PLAY_STATUS_PLAYING) {
+            //播放中
+            mGroupPlayInfo.setVisibility(View.VISIBLE);
+            mIvStatusIcon.setVisibility(View.VISIBLE);
+            mIvStatusIcon.setImageResource(R.drawable.icon_stop_play_course_ware);
+            mTvStatusText.setText("正在播放");
+            mIvPlay.setImageResource(R.drawable.icon_play_course_ware);
+            return;
+        }
+
+        if (playStatus == PLAY_STATUS_PAUSE || playStatus == PLAY_STATUS_STOP) {
+            //播放中
+            mGroupPlayInfo.setVisibility(View.VISIBLE);
+            mIvStatusIcon.setVisibility(View.VISIBLE);
+            mIvStatusIcon.setImageResource(R.drawable.icon_stop_play_course_ware);
+            mTvStatusText.setText("播放暂停");
+            mIvPlay.setImageResource(R.drawable.icon_play_course_ware);
+            return;
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        int id = v.getId();
+        if (id == R.id.iv_play) {
+            if (playStatus == PLAY_STATUS_PLAYING) {
+                getAudioMixerManager().pause();
+            }
+            if (playStatus == PLAY_STATUS_PAUSE) {
+                getAudioMixerManager().resume();
+            }
+        }
+
+        if (id == R.id.iv_status_icon) {
+            if (playStatus == PLAY_STATUS_FAIL) {
+                //刷新
+            } else {
+                stop();
+                setVisibility(View.GONE);
+            }
+        }
+    }
+
+
+    private RtcAudioMixerControl getAudioMixerManager() {
+        if (mRtcAudioMixerControl == null) {
+            mRtcAudioMixerControl = new RtcAudioMixerControl(new RtcAudioMixerControl.OnEventListener() {
+                @Override
+                public void onProgress(float progress) {
+                    Message obtain = Message.obtain();
+                    obtain.what = UPDATE_PROGRESS_TYPE;
+                    obtain.obj = progress;
+                    mHandler.sendMessage(obtain);
+                }
+
+                @Override
+                public void onStartPlay() {
+                    updatePlayCoursewareStatus(CourseWarePlayView.PLAY_STATUS_PLAYING);
+                }
+
+                @Override
+                public void onPausePlay() {
+                    updatePlayCoursewareStatus(CourseWarePlayView.PLAY_STATUS_PAUSE);
+                }
+
+                @Override
+                public void onResumePlay() {
+                    updatePlayCoursewareStatus(CourseWarePlayView.PLAY_STATUS_PLAYING);
+                }
+
+                @Override
+                public void onStop() {
+                    updatePlayCoursewareStatus(CourseWarePlayView.PLAY_STATUS_STOP);
+                }
+            });
+        }
+        return mRtcAudioMixerControl;
+    }
+
+    private void updatePlayCoursewareStatus(int playStatus) {
+        Message obtain = Message.obtain();
+        obtain.what = UPDATE_PLAY_STATUS;
+        obtain.obj = playStatus;
+        mHandler.sendMessage(obtain);
+    }
+
+
+    private void stop() {
+        getAudioMixerManager().stop();
+    }
+
+    public void release() {
+        if (mRtcAudioMixerControl != null) {
+            mRtcAudioMixerControl.stop();
+        }
+        if (mHandler != null) {
+            mHandler.removeCallbacksAndMessages(null);
+        }
+    }
 
+    public void start(String fileUrl) {
+        if (TextUtils.isEmpty(fileUrl)) {
+            return;
+        }
+        setPlayStatus(PLAY_STATUS_LOADING);
+        getAudioMixerManager().startMix(fileUrl);
     }
 }

+ 8 - 2
live_teaching/src/main/java/com/daya/live_teaching/widget/dialog/CourseWareSelectDialog.java

@@ -157,17 +157,23 @@ public class CourseWareSelectDialog extends Dialog implements View.OnClickListen
             if (onEventListener != null) {
                 CoursewareListBean.RowsBean selectCourseware = mCoursewareAdapter.getSelectCourseware();
                 if (selectCourseware != null) {
-                    onEventListener.onPlayCourseware(selectCourseware.mp3url);
+                    onEventListener.onPlayCourseware(selectCourseware.musicSheetName, getMp3Url(selectCourseware.mp3url));
+                    dismiss();
                 }
             }
             return;
         }
     }
 
+    private String getMp3Url(String mp3Url) {
+        String[] result = mp3Url.split(",");
+        return result[0];
+    }
+
     public interface OnEventListener {
         void onGetCoursewareData(String searchStr, int page);
 
-        void onPlayCourseware(String coursewareUrl);
+        void onPlayCourseware(String coursewareName, String coursewareUrl);
     }
 
     /**

BIN
live_teaching/src/main/res/drawable-xhdpi/icon_play_courseware_reload.png


BIN
live_teaching/src/main/res/drawable-xxhdpi/icon_play_courseware_reload.png


+ 1 - 0
live_teaching/src/main/res/layout/item_courseware_list_layout.xml

@@ -6,6 +6,7 @@
     android:layout_marginStart="15dp"
     android:layout_marginEnd="15dp"
     android:layout_height="52dp"
+    android:layout_marginBottom="10dp"
     android:background="@drawable/shape_514f5f_10dp">
 
     <com.cooleshow.base.widgets.QMUIRadiusImageView

+ 2 - 2
live_teaching/src/main/res/layout/view_course_ware_play_layout.xml

@@ -62,8 +62,7 @@
         android:id="@+id/seekbar"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:max="200"
-        android:progress="50"
+        android:max="100"
         android:paddingStart="6dp"
         android:paddingEnd="6dp"
         android:progressDrawable="@drawable/play_course_ware_seekbar_style"
@@ -115,5 +114,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:visibility="gone"
+        tools:visibility="visible"
         app:constraint_referenced_ids="tv_progress,tv_volume_text,iv_volume,seekbar,iv_play" />
 </androidx.constraintlayout.widget.ConstraintLayout>

BIN
rong_im/live/libs/rong_player_5.2.4.aar