Commit 1c1ed9c439a5be884f9906e5be7444a3dd850f7a

Authored by 王琳
1 parent f430b483

更新播放SDK,添加检测推流状态方法

app/libs/libcnliveutilplus.jar
No preview for this file type
app/libs/libcnlivevideo.jar
No preview for this file type
app/src/main/AndroidManifest.xml
... ... @@ -7,7 +7,9 @@
7 7 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
8 8 <uses-permission android:name="android.permission.WAKE_LOCK" />
9 9 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
10   -
  10 + <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  11 + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  12 + <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
11 13 <application
12 14 android:name="com.cnlive.demo.videoqn.VideoApplication"
13 15 android:allowBackup="true"
... ... @@ -28,6 +30,22 @@
28 30 <activity android:name="com.cnlive.demo.videoqn.CNVideoTextureActivity" />
29 31 <activity android:name="com.cnlive.demo.videoqn.VideoViewActivity" />
30 32 <activity android:name="com.cnlive.demo.videoqn.VideoFileActivity" />
  33 + <activity android:name="com.cnlive.demo.videoqn.VideoStatusActivity" />
  34 +
  35 + <service
  36 + android:name="io.rong.imlib.ipc.RongService"
  37 + android:exported="true"
  38 + android:process=":ipc" />
  39 +
  40 + <service android:name="io.rong.imlib.ReConnectService"
  41 + android:exported="true"/>
  42 +
  43 + <receiver android:name="io.rong.imlib.ConnectChangeReceiver"
  44 + android:exported="true"/>
  45 +
  46 + <receiver
  47 + android:name="io.rong.imlib.HeartbeatReceiver"
  48 + android:process=":ipc" />
31 49 </application>
32 50  
33 51 </manifest>
34 52 \ No newline at end of file
... ...
app/src/main/java/com/cnlive/demo/videoqn/CNMediaPlayerActivity.java
... ... @@ -15,6 +15,7 @@ import android.view.View;
15 15 import android.widget.FrameLayout;
16 16 import android.widget.Toast;
17 17  
  18 +import com.cnlive.demo.videoqn.model.ProgramLive;
18 19 import com.cnlive.demo.videoqn.utils.Utils;
19 20 import com.cnlive.libs.lib_cnvideo.base.IAVOptions;
20 21 import com.cnlive.libs.lib_cnvideo.base.IMediaPlayer;
... ... @@ -164,24 +165,9 @@ public class CNMediaPlayerActivity extends VideoPlayerBaseActivity {
164 165  
165 166 mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
166 167  
167   - mMediaPlayer.setDataSource(mVideoPath);
  168 +// mMediaPlayer.setDataSource(mVideoPath);
168 169 //播放视讯云视频
169   -// mMediaPlayer.setDataSource(new IDataSource() {
170   -// @Override
171   -// public String getId() {
172   -// return "qwert";
173   -// }
174   -//
175   -// @Override
176   -// public String getType() {
177   -// return Config.TYPE_LIVE;
178   -// }
179   -//
180   -// @Override
181   -// public String getRate() {
182   -// return null;
183   -// }
184   -// }, false);
  170 + mMediaPlayer.setDataSource(new ProgramLive());
185 171 mMediaPlayer.setDisplay(mSurfaceView.getHolder());
186 172 mMediaPlayer.prepareAsync();
187 173 } catch (UnsatisfiedLinkError e) {
... ... @@ -190,9 +176,10 @@ public class CNMediaPlayerActivity extends VideoPlayerBaseActivity {
190 176 e.printStackTrace();
191 177 } catch (IllegalStateException e) {
192 178 e.printStackTrace();
193   - } catch (IOException e) {
194   - e.printStackTrace();
195 179 }
  180 +// catch (IOException e) {
  181 +// e.printStackTrace();
  182 +// }
196 183 }
197 184  
198 185 private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
... ...
app/src/main/java/com/cnlive/demo/videoqn/MainActivity.java
... ... @@ -32,7 +32,8 @@ public class MainActivity extends AppCompatActivity {
32 32 "CNAudioPlayerActivity",
33 33 "CNVideoViewActivity",
34 34 "CNVideoTextureActivity",
35   - "VideoViewActivity"
  35 + "VideoViewActivity",
  36 + "VideoStatusActivity"
36 37 };
37 38  
38 39 @Override
... ... @@ -49,7 +50,7 @@ public class MainActivity extends AppCompatActivity {
49 50 TextView mVersionInfoTextView = (TextView) findViewById(R.id.version_info);
50 51 mVersionInfoTextView.setText("Version: " + BuildConfig.VERSION_NAME);
51 52  
52   - mEditText = (EditText)findViewById(R.id.VideoPathEdit);
  53 + mEditText = (EditText) findViewById(R.id.VideoPathEdit);
53 54 mEditText.setText(DEFAULT_TEST_URL);
54 55  
55 56 mStreamingTypeRadioGroup = (RadioGroup) findViewById(R.id.StreamingTypeRadioGroup);
... ... @@ -81,15 +82,23 @@ public class MainActivity extends AppCompatActivity {
81 82 public void jumpToPlayerActivity(String videopath) {
82 83 Class<?> cls = null;
83 84 switch (mActivitySpinner.getSelectedItemPosition()) {
84   - case 0: cls = CNMediaPlayerActivity.class;
  85 + case 0:
  86 + cls = CNMediaPlayerActivity.class;
85 87 break;
86   - case 1: cls = CNAudioPlayerActivity.class;
  88 + case 1:
  89 + cls = CNAudioPlayerActivity.class;
87 90 break;
88   - case 2: cls = CNVideoViewActivity.class;
  91 + case 2:
  92 + cls = CNVideoViewActivity.class;
89 93 break;
90   - case 3: cls = CNVideoTextureActivity.class;
  94 + case 3:
  95 + cls = CNVideoTextureActivity.class;
91 96 break;
92   - case 4: cls = VideoViewActivity.class;
  97 + case 4:
  98 + cls = VideoViewActivity.class;
  99 + break;
  100 + case 5:
  101 + cls = VideoStatusActivity.class;
93 102 break;
94 103 default:
95 104 return;
... ...
app/src/main/java/com/cnlive/demo/videoqn/VideoStatusActivity.java 0 → 100644
  1 +package com.cnlive.demo.videoqn;
  2 +
  3 +import android.os.Bundle;
  4 +import android.util.Log;
  5 +import android.view.View;
  6 +import android.widget.Button;
  7 +import android.widget.TextView;
  8 +import android.widget.Toast;
  9 +
  10 +import com.cnlive.demo.videoqn.model.ProgramLive;
  11 +import com.cnlive.demo.videoqn.widget.MediaController;
  12 +import com.cnlive.libs.lib_cnvideo.base.IAVOptions;
  13 +import com.cnlive.libs.lib_cnvideo.base.IMediaPlayer;
  14 +import com.cnlive.libs.lib_cnvideo.base.IVideoStatus;
  15 +import com.cnlive.libs.lib_cnvideo.base.IVideoView;
  16 +import com.cnlive.libs.lib_cnvideo.player.AVOptions;
  17 +import com.cnlive.libs.lib_cnvideo.player.VideoStatusUtil;
  18 +import com.cnlive.libs.lib_cnvideo.player.widget.CNVideoView;
  19 +
  20 +/**
  21 + * Created by Lynn on 4/7/2017.
  22 + */
  23 +
  24 +public class VideoStatusActivity extends VideoPlayerBaseActivity implements View.OnClickListener {
  25 +
  26 + private static final String TAG = "VideoStatusActivity";
  27 +
  28 + private static final int MESSAGE_ID_RECONNECTING = 0x01;
  29 +
  30 + private MediaController mMediaController;
  31 + private CNVideoView mVideoView;
  32 + private Button playBtn;
  33 + private View statusView;
  34 + private TextView statusViewText;
  35 + private Toast mToast = null;
  36 + private String mVideoPath = null;
  37 + private int mDisplayAspectRatio = CNVideoView.ASPECT_RATIO_FIT_PARENT;
  38 + private boolean mIsActivityPaused = true;
  39 +
  40 + //记录当前视频播放状态
  41 + private boolean isPlay = false;
  42 + //记录当前视频是否能播
  43 + private boolean canPlay = true;
  44 +
  45 + @Override
  46 + protected void onCreate(Bundle savedInstanceState) {
  47 + super.onCreate(savedInstanceState);
  48 + setContentView(R.layout.activity_videoview_status);
  49 + mVideoView = (CNVideoView) findViewById(R.id.videoview);
  50 + playBtn = (Button) findViewById(R.id.playerPlayPause);
  51 + playBtn.setOnClickListener(this);
  52 +
  53 + statusView = findViewById(R.id.statusView);
  54 + statusViewText = (TextView) findViewById(R.id.statusViewText);
  55 + mVideoPath = getIntent().getStringExtra("videoPath");
  56 +
  57 + AVOptions options = new AVOptions();
  58 +
  59 + int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1);
  60 + // 准备超时时间,包括创建资源、建立连接、请求码流等,单位是 ms
  61 + // 默认值是:无
  62 + options.setInteger(IAVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
  63 + // 读取视频流超时时间,单位是 ms
  64 + // 默认值是:10 * 1000
  65 + options.setInteger(IAVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
  66 + // 当前播放的是否为在线直播,如果是,则底层会有一些播放优化
  67 + // 默认值是:0
  68 + options.setInteger(IAVOptions.KEY_LIVE_STREAMING, isLiveStreaming);
  69 + if (isLiveStreaming == 1) {
  70 + // 是否开启"延时优化",只在在线直播流中有效
  71 + // 默认值是:0
  72 + options.setInteger(IAVOptions.KEY_DELAY_OPTIMIZATION, 1);
  73 + }
  74 + int codec = getIntent().getIntExtra("mediaCodec", 0);
  75 + // 解码方式,codec=1,硬解; codec=0, 软解
  76 + // 默认值是:0
  77 + options.setInteger(IAVOptions.KEY_MEDIACODEC, codec);
  78 + // 是否自动启动播放,如果设置为 1,则在调用 `prepareAsync` 或者 `setVideoPath` 之后自动启动播放,无需调用 `start()`
  79 + // 默认值是:1
  80 + options.setInteger(IAVOptions.KEY_START_ON_PREPARED, 0);
  81 + mVideoView.setAVOptions(options);
  82 +
  83 + // Set some listeners
  84 + mVideoView.setOnInfoListener(mOnInfoListener);
  85 + mVideoView.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
  86 + mVideoView.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
  87 + mVideoView.setOnCompletionListener(mOnCompletionListener);
  88 + mVideoView.setOnSeekCompleteListener(mOnSeekCompleteListener);
  89 + mVideoView.setOnErrorListener(mOnErrorListener);
  90 + mVideoView.setOnPreparedListener(onPreparedListener);
  91 + VideoStatusUtil.setOnVideoPlayStatusCallback(mOnVideoStatusCallback);
  92 +
  93 + //播放普通视频
  94 +// mVideoView.setVideoPath(mVideoPath);
  95 +
  96 + // You can also use a custom `MediaController` widget
  97 + mMediaController = new MediaController(this, false, isLiveStreaming == 1);
  98 + mVideoView.setMediaController(mMediaController);
  99 +
  100 + mVideoView.setKeepScreenOn(true);
  101 +
  102 + startPlay();
  103 + }
  104 +
  105 + private void startPlay() {
  106 + VideoStatusUtil.init("androidtest");
  107 + mVideoView.setDataSource(new ProgramLive(), false);
  108 + }
  109 +
  110 + @Override
  111 + protected void onResume() {
  112 + super.onResume();
  113 + mIsActivityPaused = false;
  114 + if (mVideoView != null && !mVideoView.isPlaying() && isPlay)
  115 + setPlayState(true);
  116 + }
  117 +
  118 + @Override
  119 + protected void onPause() {
  120 + super.onPause();
  121 + mToast = null;
  122 + mIsActivityPaused = true;
  123 + setPlayState(false);
  124 + }
  125 +
  126 + @Override
  127 + protected void onDestroy() {
  128 + super.onDestroy();
  129 + mVideoView.stopPlayback();
  130 + VideoStatusUtil.quit();
  131 + }
  132 +
  133 + public void onClickSwitchScreen(View v) {
  134 + mDisplayAspectRatio = (mDisplayAspectRatio + 1) % 5;
  135 + mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
  136 + switch (mVideoView.getDisplayAspectRatio()) {
  137 + case IVideoView.ASPECT_RATIO_ORIGIN:
  138 + showToastTips("Origin mode");
  139 + break;
  140 + case IVideoView.ASPECT_RATIO_FIT_PARENT:
  141 + showToastTips("Fit parent !");
  142 + break;
  143 + case IVideoView.ASPECT_RATIO_PAVED_PARENT:
  144 + showToastTips("Paved parent !");
  145 + break;
  146 + case IVideoView.ASPECT_RATIO_16_9:
  147 + showToastTips("16 : 9 !");
  148 + break;
  149 + case IVideoView.ASPECT_RATIO_4_3:
  150 + showToastTips("4 : 3 !");
  151 + break;
  152 + default:
  153 + break;
  154 + }
  155 + }
  156 +
  157 + private IMediaPlayer.OnPreparedListener onPreparedListener = new IMediaPlayer.OnPreparedListener() {
  158 + @Override
  159 + public void onPrepared(IMediaPlayer mp) {
  160 + Log.e("DemoView", "prepared");
  161 + if (canPlay) {
  162 + setPlayState(true);
  163 + isPlay = true;
  164 + }
  165 + }
  166 + };
  167 +
  168 + private IMediaPlayer.OnInfoListener mOnInfoListener = new IMediaPlayer.OnInfoListener() {
  169 + @Override
  170 + public boolean onInfo(IMediaPlayer plMediaPlayer, int what, int extra) {
  171 + Log.d(TAG, "onInfo: " + what + ", " + extra);
  172 + return false;
  173 + }
  174 + };
  175 +
  176 + private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
  177 + @Override
  178 + public boolean onError(IMediaPlayer plMediaPlayer, int errorCode) {
  179 + Log.e(TAG, "Error happened, errorCode = " + errorCode);
  180 + // Return true means the error has been handled
  181 + // If return false, then `onCompletion` will be called
  182 + return true;
  183 + }
  184 + };
  185 +
  186 + private IMediaPlayer.OnCompletionListener mOnCompletionListener = new IMediaPlayer.OnCompletionListener() {
  187 + @Override
  188 + public void onCompletion(IMediaPlayer plMediaPlayer) {
  189 + Log.d(TAG, "Play Completed !");
  190 + isPlay = false;
  191 + showToastTips("Play Completed !");
  192 + finish();
  193 + }
  194 + };
  195 +
  196 + private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() {
  197 + @Override
  198 + public void onBufferingUpdate(IMediaPlayer plMediaPlayer, int precent) {
  199 + Log.d(TAG, "onBufferingUpdate: " + precent);
  200 + }
  201 + };
  202 +
  203 + private IMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
  204 + @Override
  205 + public void onSeekComplete(IMediaPlayer plMediaPlayer) {
  206 + Log.d(TAG, "onSeekComplete !");
  207 + }
  208 + };
  209 +
  210 + private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() {
  211 + @Override
  212 + public void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3) {
  213 + Log.d(TAG, "onVideoSizeChanged: " + i + "," + i1 + "," + i2 + "," + i3);
  214 + }
  215 + };
  216 +
  217 + private void showToastTips(final String tips) {
  218 + if (mIsActivityPaused) {
  219 + return;
  220 + }
  221 + runOnUiThread(new Runnable() {
  222 + @Override
  223 + public void run() {
  224 + if (mToast != null) {
  225 + mToast.cancel();
  226 + }
  227 + mToast = Toast.makeText(VideoStatusActivity.this, tips, Toast.LENGTH_SHORT);
  228 + mToast.show();
  229 + }
  230 + });
  231 + }
  232 +
  233 + private IVideoStatus.VideoStatusCallback mOnVideoStatusCallback = new IVideoStatus.VideoStatusCallback() {
  234 + @Override
  235 + public void onStatusChange(int status) {
  236 + Log.e(TAG, status + "");
  237 + switch (status) {
  238 + case IVideoStatus.MEDIA_STATUS_LIVING:
  239 + //直播中'
  240 + canPlay = true;
  241 + if (mVideoView != null)
  242 + mVideoView.start();
  243 + setStatusViewVisible(false, "");
  244 + Toast.makeText(VideoStatusActivity.this, "直播中", Toast.LENGTH_LONG).show();
  245 + break;
  246 + case IVideoStatus.MEDIA_STATUS_LEAVE:
  247 + //主播暂时离开
  248 + canPlay = false;
  249 + if (mVideoView != null)
  250 + mVideoView.pause();
  251 + setStatusViewVisible(true, "主播暂时离开");
  252 + Toast.makeText(VideoStatusActivity.this, "主播暂时离开", Toast.LENGTH_LONG).show();
  253 + break;
  254 + case IVideoStatus.MEDIA_STATUS_END:
  255 + //直播结束
  256 + canPlay = false;
  257 + if (mVideoView != null)
  258 + mVideoView.stopPlayback();
  259 + setStatusViewVisible(true, "直播已经结束");
  260 + Toast.makeText(VideoStatusActivity.this, "直播结束", Toast.LENGTH_LONG).show();
  261 + break;
  262 + }
  263 +
  264 + }
  265 +
  266 + @Override
  267 + public void onError(int what, String extra) {
  268 + Log.e(TAG, "onError: " + what + "_" + extra);
  269 +// Toast.makeText(VideoStatusActivity.this, "onError: " + what + "_" + extra, Toast.LENGTH_LONG).show();
  270 + }
  271 + };
  272 +
  273 + private void setStatusViewVisible(boolean show, String warnText) {
  274 + statusView.setVisibility(show ? View.VISIBLE : View.GONE);
  275 + statusViewText.setText(warnText);
  276 + }
  277 +
  278 + private void setPlayState(boolean isPlay) {
  279 + if (isPlay) mVideoView.start();
  280 + else mVideoView.pause();
  281 + }
  282 +
  283 + @Override
  284 + public void onClick(View v) {
  285 + if (mVideoView != null) {
  286 + isPlay = !isPlay;
  287 + setPlayState(isPlay);
  288 + }
  289 + }
  290 +}
... ...
app/src/main/java/com/cnlive/demo/videoqn/model/ProgramLive.java
... ... @@ -12,19 +12,19 @@ public class ProgramLive implements IDataSource{
12 12  
13 13 //返回直播视频ID
14 14 @Override
15   - public String getId() {
16   - return "qwert";
  15 + public String getDataSourceId() {
  16 + return "androidtest";
17 17 }
18 18  
19 19 //返回视频类型 live
20 20 @Override
21   - public String getType() {
  21 + public String getDataSourceType() {
22 22 return Config.TYPE_LIVE;
23 23 }
24 24  
25 25 //返回视频码率
26 26 @Override
27   - public String getRate() {
  27 + public String getDataSourceRate() {
28 28 return Config.TYPE_PLAY_RATE_2;
29 29 }
30 30 }
... ...
app/src/main/java/com/cnlive/demo/videoqn/model/ProgramVod.java
... ... @@ -10,19 +10,19 @@ import com.cnlive.libs.util.Config;
10 10 public class ProgramVod implements IDataSource {
11 11 //返回点播视频ID
12 12 @Override
13   - public String getId() {
  13 + public String getDataSourceId() {
14 14 return "117_0005701481101785734a";
15 15 }
16 16  
17 17 //返回视频类型 vod
18 18 @Override
19   - public String getType() {
  19 + public String getDataSourceType() {
20 20 return Config.TYPE_VOD;
21 21 }
22 22  
23 23 //返回视频码率
24 24 @Override
25   - public String getRate() {
  25 + public String getDataSourceRate() {
26 26 return Config.TYPE_PLAY_RATE_2;
27 27 }
28 28 }
... ...
app/src/main/jniLibs/arm64-v8a/libRongIMLib.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libRongIMLib.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi/libRongIMLib.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/x86/libRongIMLib.so 0 → 100644
No preview for this file type
app/src/main/res/layout/activity_videoview_status.xml 0 → 100644
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical">
  6 +
  7 + <RelativeLayout
  8 + android:layout_width="match_parent"
  9 + android:layout_height="match_parent"
  10 + android:background="@android:color/black">
  11 +
  12 + <com.cnlive.libs.lib_cnvideo.player.widget.CNVideoView
  13 + android:id="@+id/videoview"
  14 + android:layout_width="match_parent"
  15 + android:layout_height="match_parent"
  16 + android:layout_centerInParent="true" />
  17 + </RelativeLayout>
  18 +
  19 + <Button
  20 + android:id="@+id/playerPlayPause"
  21 + android:layout_width="wrap_content"
  22 + android:layout_height="wrap_content"
  23 + android:layout_alignParentBottom="true"
  24 + android:text="开始" />
  25 +
  26 + <RelativeLayout
  27 + android:id="@+id/statusView"
  28 + android:layout_width="match_parent"
  29 + android:layout_height="match_parent"
  30 + android:background="@android:color/holo_blue_bright"
  31 + android:visibility="gone">
  32 +
  33 + <TextView
  34 + android:id="@+id/statusViewText"
  35 + android:layout_width="wrap_content"
  36 + android:layout_height="wrap_content"
  37 + android:layout_centerInParent="true"
  38 + android:textColor="@android:color/black" />
  39 +
  40 +
  41 + </RelativeLayout>
  42 +
  43 +</RelativeLayout>
0 44 \ No newline at end of file
... ...