提交 a6617380 authored 作者: kongdywang's avatar kongdywang

1. android pip optimize

2. superPlayerWidget pos changed 3. unified plugin log output 4. fix known issues
上级 fa52f557
#!/usr/bin/env bash
buildLog() {
echo `date +"%Y-%m-%d %H:%M:%S"`" build process: $1"
}
inputVersion=$1
export VERSION_NAME="11.8.1"
if [ -n "$inputVersion" ]; then
VERSION_NAME=$inputVersion
fi
buildLog "start config Version=${VERSION_NAME}"
buildLog "currentPathIs:$(pwd)"
buildLog "start config flutter lib pubspec version"
sed -i "" "s/version:.*$/version: $VERSION_NAME/" ../pubspec.yaml
buildLog "config success on flutter lib pubspec version"
buildLog "start config flutter lib code version"
sed -i "" "s/PLAYER_VERSION = \"[0-9.]*\"/PLAYER_VERSION = \"$VERSION_NAME\"/" ../lib/Core/common/common_config.dart
buildLog "config success on flutter lib code version"
buildLog "start config flutter superplayer_widget pubspec version"
sed -i "" "s/version:.*$/version: $VERSION_NAME/" ../superplayer_widget/pubspec.yaml
buildLog "config success on superplayer_widget pubspec version"
buildLog "start config plugin android version"
sed -i "" "s/playerVersion = \"[0-9.]*\"/playerVersion = \"$VERSION_NAME\"/" ../android/config.gradle
buildLog "config success on plugin android version"
buildLog "start config plugin ios version"
sed -i "" "s/s.version = '[0-9.]*'/s.version = '$VERSION_NAME'/" ../ios/super_player.podspec
buildLog "config success on plugin ios version"
buildLog "config Version=${VERSION_NAME} done"
\ No newline at end of file
......@@ -23,6 +23,7 @@ rootProject.allprojects {
android {
compileSdkVersion rootProject.ext.compileSdkVersion
namespace="com.tencent.vod.flutter"
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
......
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.tencent.vod.flutter">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.REORDER_TASKS" />
<application>
......
......@@ -9,7 +9,8 @@ import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.tencent.liteav.base.util.LiteavLog;
import java.util.ArrayList;
import java.util.List;
......@@ -147,7 +148,7 @@ public class FTXAudioManager {
result = mAudioManager.requestAudioFocus(afChangeListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
}
Log.e(TAG, "requestAudioFocus result:" + result);
LiteavLog.e(TAG, "requestAudioFocus result:" + result);
}
public void addAudioFocusChangedListener(AudioFocusChangeListener listener) {
......
......@@ -94,6 +94,12 @@ public class FTXEvent {
// PIP error, current interface has been destroyed.
// pip 错误,当前界面已销毁
public static final int ERROR_PIP_ACTIVITY_DESTROYED = -103;
// PIP error, miss player
// pip 错误,丢失播放器
public static final int ERROR_PIP_MISS_PLAYER = -104;
// PIP error, pip is busy
// pip 错误,已经存在画中画窗口
public static final int ERROR_PIP_IN_BUSY = -105;
// Event from PIP container,eventBus key value
// 来自画中画容器的事件,eventBus键值
public static final String EVENT_PIP_ACTION = "com.tencent.flutter.pipevent";
......@@ -134,9 +140,6 @@ public class FTXEvent {
// PIP parameters.
// 画中画参数
public static final String EXTRA_NAME_PARAMS = "pipParams";
// Video source.
// 视频源
public static final String EXTRA_NAME_VIDEO = "videoModel";
// End parameters of PIP.
// 画中画结束参数
public static final String EXTRA_NAME_RESULT = "pipResult";
......
......@@ -4,16 +4,17 @@ package com.tencent.vod.flutter;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import androidx.annotation.NonNull;
import com.tencent.liteav.base.util.LiteavLog;
import com.tencent.rtmp.ITXLivePlayListener;
import com.tencent.rtmp.TXLiveBase;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXLivePlayConfig;
import com.tencent.rtmp.TXLivePlayer;
import com.tencent.rtmp.TXVodConstants;
import com.tencent.rtmp.TXVodPlayer;
import com.tencent.vod.flutter.messages.FtxMessages.BoolMsg;
import com.tencent.vod.flutter.messages.FtxMessages.BoolPlayerMsg;
import com.tencent.vod.flutter.messages.FtxMessages.FTXLivePlayConfigPlayerMsg;
......@@ -25,8 +26,9 @@ import com.tencent.vod.flutter.messages.FtxMessages.StringIntPlayerMsg;
import com.tencent.vod.flutter.messages.FtxMessages.StringPlayerMsg;
import com.tencent.vod.flutter.messages.FtxMessages.TXFlutterLivePlayerApi;
import com.tencent.vod.flutter.model.TXPipResult;
import com.tencent.vod.flutter.model.TXVideoModel;
import com.tencent.vod.flutter.model.TXPlayerHolder;
import com.tencent.vod.flutter.tools.TXCommonUtil;
import com.tencent.vod.flutter.tools.TXFlutterEngineHolder;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.EventChannel;
......@@ -59,16 +61,23 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
private int mSurfaceHeight = 0;
private final FTXPIPManager mPipManager;
private FTXPIPManager.PipParams mPipParams;
private TXVideoModel mVideoModel;
private boolean mNeedPipResume = false;
private final FTXPIPManager.PipCallback pipCallback = new FTXPIPManager.PipCallback() {
@Override
public void onPipResult(TXPipResult result) {
// When starting PIP, if the current player is paused and PIP is still playing when exiting,
// the current player will also be set to playing state upon exiting PIP.
if (mLivePlayer != null) {
mLivePlayer.setSurface(mSurface);
mLivePlayer.setPlayListener(FTXLivePlayer.this);
}
// When starting PIP, the current player has been paused. After PIP exits,
// if PIP is still in playing state, the current player will also be set to playing state.
boolean isPipPlaying = result.isPlaying();
if (isPipPlaying) {
if (TXFlutterEngineHolder.getInstance().isInForeground()) {
resumePlayer();
} else {
mNeedPipResume = true;
}
}
}
......@@ -78,6 +87,21 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
}
};
private final TXFlutterEngineHolder.TXAppStatusListener mAppLifeListener
= new TXFlutterEngineHolder.TXAppStatusListener() {
@Override
public void onResume() {
if (mNeedPipResume) {
mNeedPipResume = false;
resumePlayer();
}
}
@Override
public void onEnterBack() {
}
};
/**
* Live streaming player.
*
......@@ -87,8 +111,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
super();
mFlutterPluginBinding = flutterPluginBinding;
mPipManager = pipManager;
mVideoModel = new TXVideoModel();
mVideoModel.setPlayerType(FTXEvent.PLAYER_LIVE);
TXFlutterEngineHolder.getInstance().addAppLifeListener(mAppLifeListener);
mSurfaceTextureEntry = mFlutterPluginBinding.getTextureRegistry().createSurfaceTexture();
mSurfaceTexture = mSurfaceTextureEntry.surfaceTexture();
......@@ -145,6 +168,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
mSurface = null;
}
TXFlutterEngineHolder.getInstance().removeAppLifeListener(mAppLifeListener);
mEventChannel.setStreamHandler(null);
mNetChannel.setStreamHandler(null);
}
......@@ -161,7 +185,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
mHardwareDecodeFail = true;
}
if (event != TXVodConstants.VOD_PLAY_EVT_PLAY_PROGRESS) {
Log.e(TAG, "onLivePlayEvent:" + event + "," + bundle.getString(TXLiveConstants.EVT_DESCRIPTION));
LiteavLog.e(TAG, "onLivePlayEvent:" + event + "," + bundle.getString(TXLiveConstants.EVT_DESCRIPTION));
}
mEventSink.success(TXCommonUtil.getParams(event, bundle));
}
......@@ -192,17 +216,15 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
mLivePlayer = new TXLivePlayer(mFlutterPluginBinding.getApplicationContext());
mLivePlayer.setPlayListener(this);
}
Log.d("AndroidLog", "textureId :" + mSurfaceTextureEntry.id());
LiteavLog.d("AndroidLog", "textureId :" + mSurfaceTextureEntry.id());
return mSurfaceTextureEntry == null ? -1 : mSurfaceTextureEntry.id();
}
int startPlayerLivePlay(String url, Integer type) {
Log.d(TAG, "startLivePlay:");
LiteavLog.d(TAG, "startLivePlay:");
if (null == type) {
type = TXLivePlayer.PLAY_TYPE_LIVE_FLV;
}
mVideoModel.setVideoUrl(url);
mVideoModel.setLiveType(type);
if (mLivePlayer != null) {
mLivePlayer.setSurface(mSurface);
mLivePlayer.setPlayListener(this);
......@@ -215,7 +237,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
int width = texture.width;
int height = texture.height;
if (width != mSurfaceWidth || height != mSurfaceHeight) {
Log.d(TAG, "onRenderVideoFrame: width=" + texture.width + ",height=" + texture.height);
LiteavLog.d(TAG, "onRenderVideoFrame: width=" + texture.width + ",height=" + texture.height);
mLivePlayer.setSurfaceSize(width, height);
mSurfaceTexture.setDefaultBufferSize(width, height);
mSurfaceWidth = width;
......@@ -429,14 +451,14 @@ public class FTXLivePlayer extends FTXBasePlayer implements ITXLivePlayListener,
@Override
public IntMsg enterPictureInPictureMode(@NonNull PipParamsPlayerMsg pipParamsMsg) {
mPipManager.addCallback(getPlayerId(), pipCallback);
mPipParams = new FTXPIPManager.PipParams(
FTXPIPManager.PipParams pipParams = new FTXPIPManager.PipParams(
mPipManager.toAndroidPath(pipParamsMsg.getBackIconForAndroid()),
mPipManager.toAndroidPath(pipParamsMsg.getPlayIconForAndroid()),
mPipManager.toAndroidPath(pipParamsMsg.getPauseIconForAndroid()),
mPipManager.toAndroidPath(pipParamsMsg.getForwardIconForAndroid()),
getPlayerId(), false, false, true);
mPipParams.setIsPlaying(isPlayerPlaying());
int pipResult = mPipManager.enterPip(mPipParams, mVideoModel);
pipParams.setIsPlaying(isPlayerPlaying());
int pipResult = mPipManager.enterPip(pipParams, new TXPlayerHolder(mLivePlayer));
// After the startup is successful, pause the video on the current interface.
if (pipResult == FTXEvent.NO_ERROR) {
pausePlayer();
......
......@@ -20,14 +20,14 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.util.Rational;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import com.tencent.liteav.base.util.LiteavLog;
import com.tencent.vod.flutter.model.TXPipResult;
import com.tencent.vod.flutter.model.TXVideoModel;
import com.tencent.vod.flutter.model.TXPlayerHolder;
import com.tencent.vod.flutter.tools.TXCommonUtil;
import com.tencent.vod.flutter.tools.TXSimpleEventBus;
import com.tencent.vod.flutter.ui.FlutterPipImplActivity;
......@@ -127,15 +127,13 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
*
* @return {@link FTXEvent} ERROR_PIP
*/
public int enterPip(PipParams params, TXVideoModel videoModel) {
public int enterPip(PipParams params, TXPlayerHolder playerHolder) {
int pipResult = isSupportDevice();
if (pipResult == FTXEvent.NO_ERROR) {
pipResult = FlutterPipImplActivity.startPip(mActivityBinding.getActivity(), params, playerHolder);
if (pipResult == FTXEvent.NO_ERROR) {
mPipEventSink.success(TXCommonUtil.getParams(FTXEvent.EVENT_PIP_MODE_REQUEST_START, null));
Intent intent = new Intent(mActivityBinding.getActivity(), FlutterPipImplActivity.class);
intent.setAction(FTXEvent.PIP_ACTION_START);
intent.putExtra(FTXEvent.EXTRA_NAME_PARAMS, params);
intent.putExtra(FTXEvent.EXTRA_NAME_VIDEO, videoModel);
mActivityBinding.getActivity().startActivity(intent);
}
mIsInPipMode = true;
}
return pipResult;
......@@ -170,19 +168,20 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
if (!isSuccess) {
pipResult = FTXEvent.ERROR_PIP_DENIED_PERMISSION;
Log.e(TAG, "enterPip failed,because PIP feature is disabled");
LiteavLog.e(TAG, "enterPip failed,because PIP feature is disabled");
} else if (!hasPipPermission(activity)) {
pipResult = FTXEvent.ERROR_PIP_DENIED_PERMISSION;
Log.e(TAG, "enterPip failed,because PIP has no permission");
LiteavLog.e(TAG, "enterPip failed,because PIP has no permission");
}
} else {
pipResult = FTXEvent.ERROR_PIP_LOWER_VERSION;
Log.e(TAG, "enterPip failed,because android version is too low,Minimum supported version is android "
+ "24,but current is " + Build.VERSION.SDK_INT);
LiteavLog.e(TAG, "enterPip failed,because android version is too low,"
+ "Minimum supported version is android 24,but current is "
+ Build.VERSION.SDK_INT);
}
} else {
pipResult = FTXEvent.ERROR_PIP_ACTIVITY_DESTROYED;
Log.e(TAG, "enterPip failed,because activity is destroyed");
LiteavLog.e(TAG, "enterPip failed,because activity is destroyed");
}
return pipResult;
}
......@@ -229,7 +228,7 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
TXSimpleEventBus.getInstance().unregister(FTXEvent.EVENT_PIP_PLAYER_EVENT_ACTION, this);
}
} catch (Exception e) {
Log.getStackTraceString(e);
LiteavLog.e(TAG, "releaseActivityListener error", e);
}
}
......@@ -262,9 +261,10 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
|| pipEventId == FTXEvent.EVENT_PIP_MODE_RESTORE_UI)) {
TXPipResult pipResult = params.getParcelable(FTXEvent.EXTRA_NAME_RESULT);
if (null != pipResult) {
callbackData.putDouble(FTXEvent.EVENT_PIP_PLAY_TIME, pipResult.getPlayTime());
callbackData.putFloat(FTXEvent.EVENT_PIP_PLAY_TIME, pipResult.getPlayTime());
handlePipResult(pipResult);
}
mIsInPipMode = false;
}
mPipEventSink.success(TXCommonUtil.getParams(pipEventId, callbackData));
} else if (TextUtils.equals(eventType, FTXEvent.EVENT_PIP_PLAYER_EVENT_ACTION)) {
......@@ -474,7 +474,7 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
return Icon.createWithBitmap(iconBitmap);
}
} catch (IOException e) {
Log.getStackTraceString(e);
LiteavLog.e(TAG, "getIcon error", e);
}
return Icon.createWithResource(activity, defaultResId);
}
......
......@@ -6,9 +6,11 @@ import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import androidx.annotation.NonNull;
import com.tencent.liteav.base.util.LiteavLog;
import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXBitrateItem;
import com.tencent.rtmp.TXImageSprite;
......@@ -36,8 +38,9 @@ import com.tencent.vod.flutter.messages.FtxMessages.StringPlayerMsg;
import com.tencent.vod.flutter.messages.FtxMessages.TXPlayInfoParamsPlayerMsg;
import com.tencent.vod.flutter.messages.FtxMessages.UInt8ListMsg;
import com.tencent.vod.flutter.model.TXPipResult;
import com.tencent.vod.flutter.model.TXVideoModel;
import com.tencent.vod.flutter.model.TXPlayerHolder;
import com.tencent.vod.flutter.tools.TXCommonUtil;
import com.tencent.vod.flutter.tools.TXFlutterEngineHolder;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
......@@ -49,7 +52,6 @@ import java.util.Map;
import java.util.Objects;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.EventChannel;
import io.flutter.view.TextureRegistry;
......@@ -73,29 +75,30 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
private TXVodPlayer mVodPlayer;
private TXImageSprite mTxImageSprite;
private TXVideoModel mVideoModel;
private static final int Uninitialized = -101;
private TextureRegistry.SurfaceTextureEntry mSurfaceTextureEntry;
private boolean mEnableHardwareDecode = true;
private boolean mHardwareDecodeFail = false;
private final FTXPIPManager mPipManager;
private FTXPIPManager.PipParams mPipParams;
private final FTXPIPManager.PipCallback pipCallback = new FTXPIPManager.PipCallback() {
private boolean mNeedPipResume = false;
private final FTXPIPManager.PipCallback mPipCallback = new FTXPIPManager.PipCallback() {
@Override
public void onPipResult(TXPipResult result) {
float playTime = result.getPlayTime();
float duration = mVodPlayer.getDuration();
if (playTime > duration) {
playTime = duration;
if (mVodPlayer != null) {
mSurface = new Surface(mSurfaceTexture);
mVodPlayer.setSurface(mSurface);
mVodPlayer.setVodListener(FTXVodPlayer.this);
}
seekPlayer(playTime);
// When starting PIP, the current player has been paused. After PIP exits,
// if PIP is still in playing state, the current player will also be set to playing state.
boolean isPipPlaying = result.isPlaying();
if (isPipPlaying) {
if (TXFlutterEngineHolder.getInstance().isInForeground()) {
playerResume();
} else {
mNeedPipResume = true;
}
}
}
......@@ -105,6 +108,21 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
}
};
private final TXFlutterEngineHolder.TXAppStatusListener mAppLifeListener
= new TXFlutterEngineHolder.TXAppStatusListener() {
@Override
public void onResume() {
if (mNeedPipResume) {
mNeedPipResume = false;
playerResume();
}
}
@Override
public void onEnterBack() {
}
};
/**
* VOD player.
*
......@@ -114,8 +132,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
super();
mPipManager = pipManager;
mFlutterPluginBinding = flutterPluginBinding;
mVideoModel = new TXVideoModel();
mVideoModel.setPlayerType(FTXEvent.PLAYER_VOD);
TXFlutterEngineHolder.getInstance().addAppLifeListener(mAppLifeListener);
mEventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "cloud.tencent"
+ ".com/txvodplayer/event/" + super.getPlayerId());
......@@ -171,6 +188,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
mEventChannel.setStreamHandler(null);
mNetChannel.setStreamHandler(null);
TXFlutterEngineHolder.getInstance().removeAppLifeListener(mAppLifeListener);
releaseTXImageSprite();
if (null != mPipManager) {
mPipManager.releaseCallback(getPlayerId());
......@@ -212,7 +230,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
mHardwareDecodeFail = true;
}
if (event != TXVodConstants.VOD_PLAY_EVT_PLAY_PROGRESS) {
Log.e(TAG, "onPlayEvent:" + event + "," + bundle.getString(TXLiveConstants.EVT_DESCRIPTION));
LiteavLog.e(TAG, "onPlayEvent:" + event + "," + bundle.getString(TXLiveConstants.EVT_DESCRIPTION));
}
mEventSink.success(TXCommonUtil.getParams(event, bundle));
}
......@@ -243,7 +261,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
return stream.toByteArray();
}
} else {
Log.e(TAG, "getImageSprite failed, time is null or initImageSprite not invoke");
LiteavLog.e(TAG, "getImageSprite failed, time is null or initImageSprite not invoke");
}
return null;
}
......@@ -291,10 +309,6 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
int startPlayerVodPlay(String url) {
if (mVodPlayer != null) {
mVideoModel.setVideoUrl(url);
mVideoModel.setAppId(0);
mVideoModel.setFileId("");
mVideoModel.setPSign("");
return mVodPlayer.startVodPlay(url);
}
return Uninitialized;
......@@ -302,10 +316,6 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
void startPlayerVodPlayWithParams(int appId, String fileId, String psign) {
if (mVodPlayer != null) {
mVideoModel.setVideoUrl("");
mVideoModel.setAppId(appId);
mVideoModel.setFileId(fileId);
mVideoModel.setPSign(psign);
TXPlayInfoParams playInfoParams = new TXPlayInfoParams(appId, fileId, psign);
mVodPlayer.startVodPlay(playInfoParams);
}
......@@ -315,6 +325,7 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
if (mVodPlayer != null) {
return mVodPlayer.stopPlay(isNeedClearLastImg);
}
mPipManager.exitPip();
releaseTXImageSprite();
mHardwareDecodeFail = false;
return Uninitialized;
......@@ -464,10 +475,8 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
if (mVodPlayer != null) {
if (TextUtils.isEmpty(token)) {
mVodPlayer.setToken(null);
mVideoModel.setToken(null);
} else {
mVodPlayer.setToken(token);
mVideoModel.setToken(token);
}
}
}
......@@ -712,23 +721,24 @@ public class FTXVodPlayer extends FTXBasePlayer implements ITXVodPlayListener, F
@NonNull
@Override
public IntMsg enterPictureInPictureMode(@NonNull PipParamsPlayerMsg pipParamsMsg) {
mPipManager.addCallback(getPlayerId(), pipCallback);
mPipParams = new FTXPIPManager.PipParams(
mPipManager.addCallback(getPlayerId(), mPipCallback);
FTXPIPManager.PipParams pipParams = new FTXPIPManager.PipParams(
mPipManager.toAndroidPath(pipParamsMsg.getBackIconForAndroid()),
mPipManager.toAndroidPath(pipParamsMsg.getPlayIconForAndroid()),
mPipManager.toAndroidPath(pipParamsMsg.getPauseIconForAndroid()),
mPipManager.toAndroidPath(pipParamsMsg.getForwardIconForAndroid()),
getPlayerId());
mPipParams.setIsPlaying(isPlayerPlaying());
mPipParams.setCurrentPlayTime(getPlayerCurrentPlaybackTime());
pipParams.setIsPlaying(isPlayerPlaying());
pipParams.setCurrentPlayTime(getPlayerCurrentPlaybackTime());
int pipResult = FTXEvent.ERROR_PIP_MISS_PLAYER;
if (null != mVodPlayer) {
mPipParams.setRadio(mVodPlayer.getWidth(), mVodPlayer.getHeight());
}
int pipResult = mPipManager.enterPip(mPipParams, mVideoModel);
pipParams.setRadio(mVodPlayer.getWidth(), mVodPlayer.getHeight());
pipResult = mPipManager.enterPip(pipParams, new TXPlayerHolder(mVodPlayer));
// After successful startup, pause the current interface video.
if (pipResult == FTXEvent.NO_ERROR) {
playerPause();
}
}
return TXCommonUtil.intMsgWith((long) pipResult);
}
......
......@@ -17,7 +17,6 @@ import android.os.Looper;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.OrientationEventListener;
import android.view.Window;
......@@ -26,6 +25,7 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.tencent.liteav.base.util.LiteavLog;
import com.tencent.rtmp.TXLiveBase;
import com.tencent.rtmp.TXLiveBaseListener;
import com.tencent.rtmp.TXPlayerGlobalSetting;
......@@ -76,12 +76,12 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
private EventChannel mEventChannel;
private EventChannel mPipEventChannel;
private FTXPlayerEventSink mEventSink = new FTXPlayerEventSink();
private final FTXPlayerEventSink mEventSink = new FTXPlayerEventSink();
private VolumeBroadcastReceiver mVolumeBroadcastReceiver;
private FlutterPluginBinding mFlutterPluginBinding;
private ActivityPluginBinding mActivityPluginBinding;
private SparseArray<FTXBasePlayer> mPlayers;
private final SparseArray<FTXBasePlayer> mPlayers = new SparseArray<>();
private FTXDownloadManager mFTXDownloadManager;
private FTXAudioManager mTxAudioManager;
......@@ -89,9 +89,8 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
private OrientationEventListener mOrientationManager;
private int mCurrentOrientation = FTXEvent.ORIENTATION_PORTRAIT_UP;
private final TXFlutterEngineHolder mEngineHolder = new TXFlutterEngineHolder();
private boolean mIsBrightnessObserverRegistered = false;
private Handler mMainHandler = new Handler(Looper.getMainLooper());
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final FTXAudioManager.AudioFocusChangeListener audioFocusChangeListener =
new FTXAudioManager.AudioFocusChangeListener() {
......@@ -116,15 +115,15 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
private final TXLiveBaseListener mSDKEvent = new TXLiveBaseListener() {
@Override
public void onLog(int level, String module, String log) {
super.onLog(level, module, log);
public void onLog(int level, String module, String liteavLog) {
super.onLog(level, module, liteavLog);
// mMainHandler.post(new Runnable() {
// @Override
// public void run() {
// Bundle params = new Bundle();
// params.putInt(FTXEvent.EVENT_LOG_LEVEL, level);
// params.putString(FTXEvent.EVENT_LOG_MODULE, module);
// params.putString(FTXEvent.EVENT_LOG_MSG, log);
// params.putString(FTXEvent.EVENT_LOG_MSG, LiteavLog);
// mEventSink.success(getParams(FTXEvent.EVENT_ON_LOG, params));
// }
// });
......@@ -180,7 +179,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
Log.i(TAG, "onAttachedToEngine");
LiteavLog.i(TAG, "onAttachedToEngine");
TXFlutterSuperPlayerPluginAPI.setup(flutterPluginBinding.getBinaryMessenger(), this);
TXFlutterNativeAPI.setup(flutterPluginBinding.getBinaryMessenger(), this);
TXFlutterVodPlayerApi.setup(flutterPluginBinding.getBinaryMessenger(), new FTXVodPlayerDispatcher(
......@@ -188,7 +187,6 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
TXFlutterLivePlayerApi.setup(flutterPluginBinding.getBinaryMessenger(), new FTXLivePlayerDispatcher(
() -> mPlayers));
mFlutterPluginBinding = flutterPluginBinding;
mPlayers = new SparseArray<>();
initAudioManagerIfNeed();
mPipEventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(),
FTXEvent.PIP_CHANNEL_NAME);
......@@ -357,7 +355,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
};
mOrientationManager.enable();
} catch (Exception e) {
Log.getStackTraceString(e);
LiteavLog.e(TAG, "innerStartVideoOrientationService error", e);
return false;
}
}
......@@ -444,7 +442,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
Log.i(TAG, "onDetachedFromEngine");
LiteavLog.i(TAG, "onDetachedFromEngine");
mFTXDownloadManager.destroy();
mFlutterPluginBinding = null;
if (null != mOrientationManager) {
......@@ -455,13 +453,13 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
if (null != mActivityPluginBinding && mActivityPluginBinding != binding) {
mEngineHolder.destroy(binding);
TXFlutterEngineHolder.getInstance().destroy(binding);
}
mActivityPluginBinding = binding;
initAudioManagerIfNeed();
initPipManagerIfNeed();
registerReceiver();
mEngineHolder.attachBindLife(binding);
TXFlutterEngineHolder.getInstance().attachBindLife(binding);
TXLiveBase.enableCustomHttpDNS(true);
TXLiveBase.setListener(mSDKEvent);
}
......@@ -485,7 +483,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
Intent serviceIntent = new Intent(mActivityPluginBinding.getActivity(), TXAndroid12BridgeService.class);
mActivityPluginBinding.getActivity().stopService(serviceIntent);
unregisterReceiver();
mEngineHolder.destroy(mActivityPluginBinding);
TXFlutterEngineHolder.getInstance().destroy(mActivityPluginBinding);
TXLiveBase.setListener(null);
}
......@@ -509,7 +507,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, ActivityAware,
mFlutterPluginBinding.getApplicationContext().getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
} catch (Exception e) {
Log.getStackTraceString(e);
LiteavLog.e(TAG, "isDeviceAutoRotateOn error", e);
return false;
}
}
......
package com.tencent.vod.flutter.model;
import com.tencent.rtmp.TXLivePlayer;
import com.tencent.rtmp.TXVodPlayer;
import com.tencent.vod.flutter.FTXEvent;
public class TXPlayerHolder {
private TXVodPlayer mVodPlayer;
private TXLivePlayer mLivePlayer;
private int mPlayerType;
private boolean mInitPlayingStatus;
public TXPlayerHolder(TXVodPlayer vodPlayer) {
mVodPlayer = vodPlayer;
mInitPlayingStatus = vodPlayer.isPlaying();
mPlayerType = FTXEvent.PLAYER_VOD;
}
public TXPlayerHolder(TXLivePlayer livePlayer) {
mLivePlayer = livePlayer;
mInitPlayingStatus = livePlayer.isPlaying();
mPlayerType = FTXEvent.PLAYER_LIVE;
}
public TXVodPlayer getVodPlayer() {
return mVodPlayer;
}
public TXLivePlayer getLivePlayer() {
return mLivePlayer;
}
public boolean isPlayingWhenCreate() {
return mInitPlayingStatus;
}
public void tmpPause() {
if (null != mVodPlayer) {
mVodPlayer.pause();
} else if (null != mLivePlayer) {
mLivePlayer.pause();
}
}
public int getPlayerType() {
return mPlayerType;
}
}
// Copyright (c) 2022 Tencent. All rights reserved.
package com.tencent.vod.flutter.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.tencent.rtmp.TXLivePlayer;
import com.tencent.vod.flutter.FTXEvent;
/**
* Video model.
*
* 视频model
*/
public class TXVideoModel implements Parcelable {
private String videoUrl;
private int appId;
private String fileId;
private String pSign;
private int mPlayerType = FTXEvent.PLAYER_VOD;
private int mLiveType = TXLivePlayer.PLAY_TYPE_LIVE_FLV;
private String mToken;
public TXVideoModel() {}
protected TXVideoModel(Parcel in) {
videoUrl = in.readString();
appId = in.readInt();
fileId = in.readString();
pSign = in.readString();
mPlayerType = in.readInt();
mLiveType = in.readInt();
mToken = in.readString();
}
public static final Creator<TXVideoModel> CREATOR = new Creator<TXVideoModel>() {
@Override
public TXVideoModel createFromParcel(Parcel in) {
return new TXVideoModel(in);
}
@Override
public TXVideoModel[] newArray(int size) {
return new TXVideoModel[size];
}
};
public String getVideoUrl() {
return videoUrl;
}
public void setVideoUrl(String videoUrl) {
this.videoUrl = videoUrl;
}
public String getToken() {
return mToken;
}
public void setToken(String token) {
this.mToken = token;
}
public int getAppId() {
return appId;
}
public void setAppId(int appId) {
this.appId = appId;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getPSign() {
return pSign;
}
public void setPSign(String pSign) {
this.pSign = pSign;
}
public int getPlayerType() {
return mPlayerType;
}
public void setPlayerType(int mPlayerType) {
this.mPlayerType = mPlayerType;
}
public int getLiveType() {
return mLiveType;
}
public void setLiveType(int mLiveType) {
this.mLiveType = mLiveType;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(videoUrl);
dest.writeInt(appId);
dest.writeString(fileId);
dest.writeString(pSign);
dest.writeInt(mPlayerType);
dest.writeInt(mLiveType);
dest.writeString(mToken);
}
}
......@@ -6,8 +6,8 @@ import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import com.tencent.liteav.base.util.LiteavLog;
import com.tencent.rtmp.downloader.TXVodDownloadMediaInfo;
import com.tencent.vod.flutter.FTXEvent;
import com.tencent.vod.flutter.messages.FtxMessages.BoolMsg;
......@@ -68,7 +68,7 @@ public class TXCommonUtil {
maxBrightness = system.getInteger(resId);
}
} catch (Exception e) {
Log.getStackTraceString(e);
LiteavLog.e(TAG, "getBrightnessMax error", e);
}
if (TXCommonUtil.isMIUI() && Build.VERSION.SDK_INT >= 33) {
maxBrightness = 128F;
......
......@@ -7,19 +7,35 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.Log;
import com.tencent.liteav.base.util.LiteavLog;
import java.util.ArrayList;
import java.util.List;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
public class TXFlutterEngineHolder {
private static final String TAG = "TXFlutterEngineHolder";
private static final class SingletonInstance {
private static TXFlutterEngineHolder instance = new TXFlutterEngineHolder();
}
private int mFrontContextCount = 0;
private Application.ActivityLifecycleCallbacks mLifeCallback;
private final List<TXAppStatusListener> mListeners = new ArrayList<>();
private boolean mIsEnterBack = false;
private final List<Activity> mActivityList = new ArrayList<>();
public static TXFlutterEngineHolder getInstance() {
return SingletonInstance.instance;
}
public void attachBindLife(ActivityPluginBinding binding) {
if (mLifeCallback != null) {
Log.w(TAG, "TXFlutterEngineHolder is already attach");
LiteavLog.w(TAG, "TXFlutterEngineHolder is already attach");
return;
}
if (null == binding) {
......@@ -32,6 +48,7 @@ public class TXFlutterEngineHolder {
return;
}
mLifeCallback = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
......@@ -40,11 +57,23 @@ public class TXFlutterEngineHolder {
@Override
public void onActivityStarted(@NonNull Activity activity) {
mFrontContextCount++;
if (mIsEnterBack && mFrontContextCount > 0) {
mIsEnterBack = false;
notifyResume();
}
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
synchronized (mActivityList) {
if (mActivityList.contains(activity)) {
// refresh index
mActivityList.remove(activity);
mActivityList.add(activity);
} else {
mActivityList.add(activity);
}
}
}
@Override
......@@ -55,6 +84,10 @@ public class TXFlutterEngineHolder {
@Override
public void onActivityStopped(@NonNull Activity activity) {
mFrontContextCount--;
if (!mIsEnterBack && mFrontContextCount <= 0) {
mIsEnterBack = true;
notifyEnterBack();
}
}
@Override
......@@ -64,14 +97,33 @@ public class TXFlutterEngineHolder {
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
synchronized (mActivityList) {
mActivityList.remove(activity);
}
}
};
binding.getActivity().getApplication().registerActivityLifecycleCallbacks(mLifeCallback);
}
public boolean isInForeground() {
return mFrontContextCount > 0;
return !mIsEnterBack;
}
public Activity getActivityByIndex(int index) {
synchronized (mActivityList) {
if (index >= mActivityList.size() || index < 0) {
return null;
}
return mActivityList.get(index);
}
}
public Activity getPreActivity() {
synchronized (mActivityList) {
final int size = mActivityList.size();
final int preIndex = size - 2;
return getActivityByIndex(preIndex);
}
}
public void destroy(ActivityPluginBinding binding) {
......@@ -89,4 +141,46 @@ public class TXFlutterEngineHolder {
}
binding.getActivity().getApplication().unregisterActivityLifecycleCallbacks(mLifeCallback);
}
public void addAppLifeListener(TXAppStatusListener listener) {
synchronized (mListeners) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
}
}
}
public void removeAppLifeListener(TXAppStatusListener listener) {
synchronized (mListeners) {
mListeners.remove(listener);
}
}
public void clearListener() {
synchronized (mListeners) {
mListeners.clear();
}
}
private void notifyResume() {
synchronized (mListeners) {
for (TXAppStatusListener listener : mListeners) {
listener.onResume();
}
}
}
private void notifyEnterBack() {
synchronized (mListeners) {
for (TXAppStatusListener listener : mListeners) {
listener.onEnterBack();
}
}
}
public abstract static class TXAppStatusListener {
public abstract void onResume();
public abstract void onEnterBack();
}
}
......@@ -3,7 +3,6 @@
package com.tencent.vod.flutter.ui;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.app.PictureInPictureUiState;
import android.content.BroadcastReceiver;
......@@ -13,6 +12,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Build.VERSION;
......@@ -21,7 +21,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
......@@ -32,27 +31,28 @@ import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.tencent.liteav.base.util.LiteavLog;
import com.tencent.rtmp.ITXLivePlayListener;
import com.tencent.rtmp.ITXVodPlayListener;
import com.tencent.rtmp.TXLiveConstants;
import com.tencent.rtmp.TXLivePlayer;
import com.tencent.rtmp.TXPlayInfoParams;
import com.tencent.rtmp.TXVodPlayConfig;
import com.tencent.rtmp.TXVodConstants;
import com.tencent.rtmp.TXVodPlayer;
import com.tencent.vod.flutter.FTXEvent;
import com.tencent.vod.flutter.FTXPIPManager.PipParams;
import com.tencent.vod.flutter.R;
import com.tencent.vod.flutter.model.TXPipResult;
import com.tencent.vod.flutter.model.TXVideoModel;
import com.tencent.vod.flutter.model.TXPlayerHolder;
import com.tencent.vod.flutter.tools.TXFlutterEngineHolder;
import com.tencent.vod.flutter.tools.TXSimpleEventBus;
import java.util.List;
import java.util.Set;
public class FlutterPipImplActivity extends Activity implements Callback, ITXVodPlayListener,
ITXLivePlayListener, ServiceConnection {
private static final String TAG = "FlutterPipImplActivity";
private static TXPlayerHolder pipPlayerHolder;
private static boolean isInPip = false;
/**
* Here, `needToExitPip` is used as a flag. When the `onPictureInPictureModeChanged` callback picture-in-picture
......@@ -60,7 +60,7 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
* interface change are detected in `onConfigurationChanged`, the event notification of exiting
* picture-in-picture mode is performed.
* for MIUI 12.5.1.
*
* <p>
* 这里使用needToExitPip作为标志位,在出现onPictureInPictureModeChanged回调画中画状态和isInPictureInPictureMode不一致的时候。
* 标记为true,然后在onConfigurationChanged监听到界面宽高发生变化的时候,进行画中画模式退出的事件通知。
* for MIUI 12.5.1
......@@ -72,17 +72,16 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
private SurfaceView mVideoSurface;
private ProgressBar mVideoProgress;
private TXVodPlayer mVodPlayer;
private TXLivePlayer mLivePlayer;
private boolean mIsSurfaceCreated = false;
// In picture-in-picture mode, clicking the X in the upper right corner will trigger `onStop` first.
// Clicking the zoom button will not trigger `onStop`.
private boolean mIsNeedToStop = false;
private TXVideoModel mVideoModel;
private boolean mIsRegisterReceiver = false;
private PipParams mCurrentParams;
private Handler mMainHandler;
private boolean mIsPipFinishing = false;
private TXPlayerHolder mPlayerHolder;
private boolean mIsPlayEnd = false;
private final BroadcastReceiver pipActionReceiver = new BroadcastReceiver() {
@Override
......@@ -103,7 +102,7 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
handlePlayForward();
break;
default:
Log.e(TAG, "unknown control code");
LiteavLog.e(TAG, "unknown control code");
break;
}
}
......@@ -111,6 +110,30 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
}
};
public static int startPip(Activity activity, PipParams params, TXPlayerHolder playerHolder) {
if (null == playerHolder) {
LiteavLog.e(TAG, "startPip failed, playerHolder is null");
return FTXEvent.ERROR_PIP_MISS_PLAYER;
}
if (null == playerHolder.getLivePlayer() && null == playerHolder.getVodPlayer()) {
LiteavLog.e(TAG, "startPip failed, all player is null");
return FTXEvent.ERROR_PIP_MISS_PLAYER;
}
if (isInPip) {
LiteavLog.e(TAG, "startPip failed, pip is busy");
return FTXEvent.ERROR_PIP_IN_BUSY;
}
isInPip = true;
// pause first, resume video after entered pip
playerHolder.tmpPause();
pipPlayerHolder = playerHolder;
Intent intent = new Intent(activity, FlutterPipImplActivity.class);
intent.setAction(FTXEvent.PIP_ACTION_START);
intent.putExtra(FTXEvent.EXTRA_NAME_PARAMS, params);
activity.startActivity(intent);
return FTXEvent.NO_ERROR;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......@@ -118,15 +141,27 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
bindAndroid12BugServiceIfNeed();
registerPipBroadcast();
setContentView(R.layout.activity_flutter_pip_impl);
mVodPlayer = new TXVodPlayer(this);
mLivePlayer = new TXLivePlayer(this);
mVideoSurface = findViewById(R.id.sv_video_container);
mVideoProgress = findViewById(R.id.pb_video_progress);
mVideoSurface.getHolder().addCallback(this);
if (null == pipPlayerHolder) {
LiteavLog.e(TAG, "lack pipPlayerHolder, please check the pip argument");
finish();
return;
}
mPlayerHolder = pipPlayerHolder;
if (null != mPlayerHolder.getVodPlayer()) {
setVodPlayerListener();
} else if (null != mPlayerHolder.getLivePlayer()) {
setLivePlayerListener();
} else {
LiteavLog.e(TAG, "lack pipPlayerHolder player, please check the pip argument");
finish();
}
Intent intent = getIntent();
PipParams params = intent.getParcelableExtra(FTXEvent.EXTRA_NAME_PARAMS);
if (null == params) {
Log.e(TAG, "lack pip params,please check the intent argument");
LiteavLog.e(TAG, "lack pip params,please check the argument");
finish();
} else {
mCurrentParams = params;
......@@ -136,19 +171,16 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
configPipMode(null);
}
}
setVodPlayerListener();
setLivePlayerListener();
handleIntent(intent);
}
private void setVodPlayerListener() {
// set default config
mVodPlayer.setConfig(new TXVodPlayConfig());
mVodPlayer.setVodListener(this);
mPlayerHolder.getVodPlayer().setVodListener(this);
}
private void setLivePlayerListener() {
mLivePlayer.setPlayListener(this);
mPlayerHolder.getLivePlayer().setPlayListener(this);
}
@Override
......@@ -170,7 +202,7 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
/**
* To be compatible with MIUI 12.5, in PIP mode, if you open another app and then swipe up to exit,
* and then click the PIP window, `onPictureInPictureModeChanged` will be abnormally called back to close.
*
* <p>
* 为了兼容MIUI 12.5,PIP模式下,打开其他app然后上滑退出,再点击画中画窗口,onPictureInPictureModeChanged会异常回调关闭的情况
*
* @param ignore 校对画中画状态 Verify picture-in-picture status.
......@@ -207,7 +239,7 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
/**
* Callback notification after `enterPictureInPictureMode` takes effect, only for Android > 31.
*
* <p>
* enterPictureInPictureMode生效后的回调通知,only for android > 31
*/
@Override
......@@ -221,7 +253,7 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
}
private void configPipMode(PictureInPictureParams params) {
mVideoSurface.postDelayed(new Runnable() {
mVideoSurface.post(new Runnable() {
@Override
public void run() {
if (VERSION.SDK_INT >= VERSION_CODES.N) {
......@@ -232,7 +264,7 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
}
}
}
}, 200);
});
}
private void registerPipBroadcast() {
......@@ -253,17 +285,32 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
private void handlePipExitEvent() {
Bundle data = new Bundle();
TXPipResult pipResult = new TXPipResult();
if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_VOD) {
Float currentPlayTime = mVodPlayer.getCurrentPlaybackTime();
if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_VOD) {
if (mIsPlayEnd) {
pipResult.setPlayTime(0F);
} else {
Float currentPlayTime = mPlayerHolder.getVodPlayer().getCurrentPlaybackTime();
pipResult.setPlayTime(currentPlayTime);
pipResult.setPlaying(mVodPlayer.isPlaying());
}
pipResult.setPlaying(mPlayerHolder.getVodPlayer().isPlaying());
pipResult.setPlayerId(mCurrentParams.getCurrentPlayerId());
data.putParcelable(FTXEvent.EXTRA_NAME_RESULT, pipResult);
} else if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_LIVE) {
pipResult.setPlaying(mLivePlayer.isPlaying());
} else if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_LIVE) {
pipResult.setPlaying(mPlayerHolder.getLivePlayer().isPlaying());
pipResult.setPlayerId(mCurrentParams.getCurrentPlayerId());
data.putParcelable(FTXEvent.EXTRA_NAME_RESULT, pipResult);
}
if (null != mPlayerHolder.getVodPlayer()) {
mPlayerHolder.getVodPlayer().setSurface(null);
}
if (null != mPlayerHolder.getLivePlayer()) {
mPlayerHolder.getLivePlayer().setSurface(null);
}
if (null != mPlayerHolder.getVodPlayer()) {
mPlayerHolder.getVodPlayer().pause();
} else if (null != mPlayerHolder.getLivePlayer()) {
mPlayerHolder.getLivePlayer().pause();
}
int codeEvent = mIsNeedToStop ? FTXEvent.EVENT_PIP_MODE_ALREADY_EXIT : FTXEvent.EVENT_PIP_MODE_RESTORE_UI;
sendPipEvent(codeEvent, data);
exitPip(codeEvent == FTXEvent.EVENT_PIP_MODE_ALREADY_EXIT);
......@@ -279,14 +326,14 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
if (intent != null) {
String action = intent.getAction();
if (TextUtils.equals(action, FTXEvent.PIP_ACTION_START)) {
startPipVideoFromIntent(intent);
startPipVideo();
} else if (TextUtils.equals(action, FTXEvent.PIP_ACTION_EXIT)) {
exitPip(true);
} else if (TextUtils.equals(action, FTXEvent.PIP_ACTION_UPDATE)) {
PipParams pipParams = intent.getParcelableExtra(FTXEvent.EXTRA_NAME_PARAMS);
updatePip(pipParams);
} else {
Log.e(TAG, "unknown pip action:" + action);
LiteavLog.e(TAG, "unknown pip action:" + action);
}
}
}
......@@ -303,26 +350,20 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
/**
* move task to from。Prevent the issue of picture-in-picture windows failing to launch the app in certain cases.
*/
public void moveAppToFront() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}
ActivityManager activityManager =
(ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
for (ActivityManager.AppTask task : appTasks) {
final Intent baseIntent = task.getTaskInfo().baseIntent;
final Set<String> categories = baseIntent.getCategories();
if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
task.moveToFront();
return;
public void movePreActToFront() {
if (VERSION.SDK_INT == VERSION_CODES.Q) {
Activity activity = TXFlutterEngineHolder.getInstance().getPreActivity();
if (null != activity) {
Intent intent = new Intent(FlutterPipImplActivity.this, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
}
}
}
/**
* Close picture-in-picture mode by using `finish` to close the current interface.
*
* <p>
* 关闭画中画,使用finish当前界面的方式,关闭画中画
*
* @param closeImmediately 立刻关闭,不执行延迟,一般关闭画中画为true,还原画中画为false。
......@@ -338,36 +379,27 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
// Due to the foreground service startup restriction in Android 12, if the activity interface is closed
// too early after returning from picture-in-picture mode, the app cannot be launched normally.
// Therefore, a delay processing is added here.
if (VERSION.SDK_INT >= VERSION_CODES.S && !closeImmediately) {
mVodPlayer.stopPlay(true);
mLivePlayer.stopPlay(true);
if (!closeImmediately) {
mVideoSurface.setVisibility(View.GONE);
mVideoProgress.setVisibility(View.GONE);
mMainHandler.postDelayed(new Runnable() {
@Override
public void run() {
overridePendingTransition(0, 0);
finishAndRemoveTask();
finish();
mIsPipFinishing = false;
movePreActToFront();
}
}, 500);
} else {
overridePendingTransition(0, 0);
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
finishAndRemoveTask();
} else {
finish();
}
mIsPipFinishing = false;
}
}
if (!closeImmediately) {
moveAppToFront();
}
}
private void startPipVideoFromIntent(Intent intent) {
mVideoModel = (TXVideoModel) intent.getParcelableExtra(FTXEvent.EXTRA_NAME_VIDEO);
private void startPipVideo() {
if (mIsSurfaceCreated) {
attachSurface(mVideoSurface.getHolder().getSurface());
startPlay();
......@@ -375,29 +407,12 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
}
private void startPlay() {
if (null != mVideoModel) {
float playTime = mCurrentParams.getCurrentPlayTime();
boolean isPlaying = mCurrentParams.isPlaying();
if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_VOD) {
mVodPlayer.setStartTime(playTime);
mVodPlayer.setAutoPlay(isPlaying);
mVodPlayer.setToken(mVideoModel.getToken());
if (!TextUtils.isEmpty(mVideoModel.getVideoUrl())) {
mVodPlayer.startVodPlay(mVideoModel.getVideoUrl());
} else if (!TextUtils.isEmpty(mVideoModel.getFileId())) {
mVodPlayer.startVodPlay(
new TXPlayInfoParams(mVideoModel.getAppId(), mVideoModel.getFileId(),
mVideoModel.getPSign()));
}
} else if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_LIVE) {
mVideoProgress.setProgress(mVideoProgress.getMax());
mLivePlayer.startLivePlay(mVideoModel.getVideoUrl(), mVideoModel.getLiveType());
// Live broadcast does not currently support picture-in-picture mode and
// pausing the live broadcast when entering picture-in-picture mode.
mCurrentParams.setIsPlaying(true);
if (VERSION.SDK_INT >= VERSION_CODES.O) {
setPictureInPictureParams(mCurrentParams.buildParams(this));
}
boolean isInitPlaying = pipPlayerHolder.isPlayingWhenCreate();
if (isInitPlaying) {
if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_VOD) {
mPlayerHolder.getVodPlayer().resume();
} else if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_LIVE) {
mPlayerHolder.getLivePlayer().resume();
}
}
}
......@@ -416,16 +431,12 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mVodPlayer.setSurface(null);
mLivePlayer.setSurface(null);
mIsSurfaceCreated = false;
}
@Override
protected void onStop() {
super.onStop();
mVodPlayer.stopPlay(true);
mLivePlayer.stopPlay(true);
mIsNeedToStop = true;
}
......@@ -441,6 +452,9 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
if (Build.VERSION.SDK_INT >= VERSION_CODES.S) {
unbindService(this);
}
mPlayerHolder = null;
pipPlayerHolder = null;
isInPip = false;
super.onDestroy();
}
......@@ -454,42 +468,49 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
}
private void attachSurface(Surface surface) {
if (null != mVideoModel) {
if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_VOD) {
mVodPlayer.setSurface(surface);
} else if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_LIVE) {
mLivePlayer.setSurface(surface);
if (null != mPlayerHolder) {
if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_VOD) {
mPlayerHolder.getVodPlayer().setSurface(surface);
} else if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_LIVE) {
mPlayerHolder.getLivePlayer().setSurface(surface);
} else {
Log.e(TAG, "unknown player type:" + mVideoModel.getPlayerType());
LiteavLog.e(TAG, "unknown player type:" + mPlayerHolder.getPlayerType());
}
} else {
Log.e(TAG, "pip video model is null");
LiteavLog.e(TAG, "pip video model is null");
}
}
private void handlePlayBack() {
if (mVodPlayer.isPlaying()) {
float backPlayTime = mVodPlayer.getCurrentPlaybackTime() - 10;
if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_VOD) {
TXVodPlayer vodPlayer = mPlayerHolder.getVodPlayer();
if (vodPlayer.isPlaying()) {
float backPlayTime = vodPlayer.getCurrentPlaybackTime() - 10;
if (backPlayTime < 0) {
backPlayTime = 0;
}
mVodPlayer.seek(backPlayTime);
vodPlayer.seek(backPlayTime);
}
}
}
private void handleResumeOrPause() {
boolean dstPlaying = !mVodPlayer.isPlaying();
if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_VOD) {
boolean dstPlaying = false;
if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_VOD) {
TXVodPlayer vodPlayer = mPlayerHolder.getVodPlayer();
dstPlaying = !vodPlayer.isPlaying();
if (dstPlaying) {
mVodPlayer.resume();
vodPlayer.resume();
} else {
mVodPlayer.pause();
vodPlayer.pause();
}
} else if (mVideoModel.getPlayerType() == FTXEvent.PLAYER_LIVE) {
} else if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_LIVE) {
TXLivePlayer livePlayer = mPlayerHolder.getLivePlayer();
dstPlaying = !livePlayer.isPlaying();
if (dstPlaying) {
mLivePlayer.resume();
livePlayer.resume();
} else {
mLivePlayer.pause();
livePlayer.pause();
}
}
mCurrentParams.setIsPlaying(dstPlaying);
......@@ -497,13 +518,16 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
}
private void handlePlayForward() {
if (mVodPlayer.isPlaying()) {
float forwardPlayTime = mVodPlayer.getCurrentPlaybackTime() + 10;
float duration = mVodPlayer.getDuration();
if (mPlayerHolder.getPlayerType() == FTXEvent.PLAYER_VOD) {
TXVodPlayer vodPlayer = mPlayerHolder.getVodPlayer();
if (vodPlayer.isPlaying()) {
float forwardPlayTime = vodPlayer.getCurrentPlaybackTime() + 10;
float duration = vodPlayer.getDuration();
if (forwardPlayTime > duration) {
forwardPlayTime = duration;
}
mVodPlayer.seek(forwardPlayTime);
vodPlayer.seek(forwardPlayTime);
}
}
}
......@@ -511,8 +535,8 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
if (null == data) {
data = new Bundle();
}
data.putInt(FTXEvent.EVENT_PIP_MODE_NAME, eventCode);
data.putInt(FTXEvent.EXTRA_NAME_PLAYER_ID, mCurrentParams.getCurrentPlayerId());
data.putInt(FTXEvent.EVENT_PIP_MODE_NAME, eventCode);
TXSimpleEventBus.getInstance().post(FTXEvent.EVENT_PIP_ACTION, data);
}
......@@ -521,13 +545,14 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
* To prevent the black screen at the moment when picture-in-picture is started,
* the component is initially in a hidden state, and the component will only be displayed
* after entering picture-in-picture mode.
*
* <p>
* 显示组件
* 为了防止画中画启动一瞬间的黑屏,组件一开始为隐藏状态,只有进入画中画之后才会显示组件
*/
private void showComponent() {
mVideoSurface.setVisibility(View.VISIBLE);
mVideoProgress.setVisibility(View.VISIBLE);
mVideoSurface.setBackgroundColor(Color.parseColor("#33000000"));
}
private void controlPipPlayStatus(boolean isPlaying) {
......@@ -553,9 +578,11 @@ public class FlutterPipImplActivity extends Activity implements Callback, ITXVod
}
if (event == TXLiveConstants.PLAY_EVT_PLAY_END) {
// When playback is complete, automatically set the playback button to play.
mIsPlayEnd = true;
controlPipPlayStatus(false);
} else if (event == TXLiveConstants.PLAY_EVT_PLAY_BEGIN) {
// When playback starts, automatically set the playback button to pause.
mIsPlayEnd = false;
controlPipPlayStatus(true);
} else if (event == TXLiveConstants.PLAY_EVT_PLAY_PROGRESS) {
int progress = bundle.getInt(TXLiveConstants.EVT_PLAY_PROGRESS_MS);
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
tools:context="com.tencent.vod.flutter.ui.FlutterPipImplActivity">
<SurfaceView
android:id="@+id/sv_video_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:visibility="gone"/>
android:visibility="gone" />
<ProgressBar
android:id="@+id/pb_video_progress"
style="@android:style/Widget.Holo.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_alignParentBottom="true"
android:max="100"
android:visibility="gone"
style="@android:style/Widget.Holo.ProgressBar.Horizontal"/>
android:visibility="gone" />
</RelativeLayout>
\ No newline at end of file
......@@ -27,11 +27,12 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 33
namespace="com.example.flutter.player"
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.tencent.liteav.demo"
minSdkVersion 19
targetSdkVersion 31
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
......@@ -44,7 +45,7 @@ android {
}
debug {
minifyEnabled true // 关闭混淆
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.player">
>
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.player">
>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.player">
>
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
......
......@@ -20,6 +20,8 @@ class _DemoShortVideoPlayerState extends State<DemoShortVideoPlayer> with Widget
@override
void initState() {
super.initState();
// stop pip window if exists
TXPipController.instance.exitAndReleaseCurrentPip();
ShortVideoDataLoader loader = ShortVideoDataLoader();
loader.getPageListDataOneByOneFunction((dataModels) {
setState(() {
......
......@@ -118,7 +118,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
),
),
),
onWillPop: onWillPop);
onWillPop: onWillPop,);
}
Future<bool> onWillPop() async {
......@@ -217,7 +217,9 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
onTap: () => playCurrentModel(playModel, 0),
horizontalTitleGap: 10,
),
Divider()
Divider(
color: Colors.transparent,
)
],
);
}
......
......@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:super_player/super_player.dart';
import 'package:super_player_example/res/app_localizations.dart';
import 'package:superplayer_widget/demo_superplayer_lib.dart';
import 'ui/demo_inputdialog.dart';
import 'ui/demo_volume_slider.dart';
......@@ -94,6 +95,8 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
@override
void initState() {
super.initState();
// stop pip window if exists
TXPipController.instance.exitAndReleaseCurrentPip();
init();
WidgetsBinding.instance.addObserver(this);
EasyLoading.show(status: 'loading...');
......
......@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'dart:async';
import 'package:super_player/super_player.dart';
import 'package:super_player_example/res/app_localizations.dart';
import 'package:superplayer_widget/demo_superplayer_lib.dart';
import 'ui/demo_inputdialog.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'ui/demo_volume_slider.dart';
......@@ -102,6 +103,8 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> with WidgetsBindingOb
@override
void initState() {
super.initState();
// stop pip window if exists
TXPipController.instance.exitAndReleaseCurrentPip();
_controller = TXVodPlayerController();
init();
WidgetsBinding.instance.addObserver(this);
......
......@@ -5,7 +5,7 @@ import 'package:super_player/super_player.dart';
/// progress slider widget
class VideoSliderView extends StatefulWidget {
final ChangeNotifier _controller;
final TXPlayerController _controller;
VideoSliderView(this._controller,Key key):super(key: key);
......
......@@ -27,7 +27,7 @@ dependencies:
path: ../
superplayer_widget:
# 该路径根据superplayer_widget存放路径改变
path: ../superplayer_widget
path: ../../FlutterWidget/superplayer_widget
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
......
......@@ -9,6 +9,7 @@
#import <libkern/OSAtomic.h>
#import "FtxMessages.h"
#import "TXCommonUtil.h"
#import "FTXLog.h"
static const int uninitialized = -1;
......@@ -301,7 +302,7 @@ static const int uninitialized = -1;
- (void)onPlayEvent:(int)EvtID withParam:(NSDictionary *)param
{
[_eventSink success:[FTXLivePlayer getParamsWithEvent:EvtID withParams:param]];
NSLog(@"onLivePlayEvent:%i,%@", EvtID, param[EVT_PLAY_DESCRIPTION]);
FTXLOGI(@"onLivePlayEvent:%i,%@", EvtID, param[EVT_PLAY_DESCRIPTION])
}
/**
......
......@@ -11,6 +11,7 @@
#import "FTXEvent.h"
#import "FtxMessages.h"
#import "TXCommonUtil.h"
#import "FTXLog.h"
static const int uninitialized = -1;
static const int CODE_ON_RECEIVE_FIRST_FRAME = 2003;
......@@ -375,7 +376,7 @@ static const int CODE_ON_RECEIVE_FIRST_FRAME = 2003;
return data;
}
} else {
NSLog(@"getImageSprite failed, time is null or initImageSprite not invoke");
FTXLOGE(@"getImageSprite failed, time is null or initImageSprite not invoke");
}
return nil;
}
......@@ -462,7 +463,7 @@ static const int CODE_ON_RECEIVE_FIRST_FRAME = 2003;
});
}
if (EvtID != PLAY_EVT_PLAY_PROGRESS) {
NSLog(@"onPlayEvent:%i,%@", EvtID, param[EVT_PLAY_DESCRIPTION]);
FTXLOGI(@"onPlayEvent:%i,%@", EvtID, param[EVT_PLAY_DESCRIPTION]);
}
[_eventSink success:[FTXVodPlayer getParamsWithEvent:EvtID withParams:param]];
}
......@@ -786,7 +787,7 @@ static const int CODE_ON_RECEIVE_FIRST_FRAME = 2003;
break;
}
self.hasEnteredPipMode = NO;
NSLog(@"[onPlayer], pictureInPictureErrorDidOccur errorType= %ld", type);
FTXLOGE(@"[onPlayer], pictureInPictureErrorDidOccur errorType= %ld", type);
if (self.delegate && [self.delegate respondsToSelector:@selector(onPlayerPipStateError:)]) {
[self.delegate onPlayerPipStateError:type];
}
......
......@@ -12,6 +12,7 @@
#import "FtxMessages.h"
#import "FTXVodPlayerDispatcher.h"
#import "FTXLivePlayerDispatcher.h"
#import "FTXLog.h"
@interface SuperPlayerPlugin ()<FlutterStreamHandler,FTXVodPlayerDelegate,TXFlutterSuperPlayerPluginAPI,TXFlutterNativeAPI, ITXPlayersBridge, FlutterPlugin, TXLiveBaseDelegate>
......@@ -303,6 +304,7 @@ SuperPlayerPlugin* instance;
- (void)setLogLevelLogLevel:(nonnull IntMsg *)logLevel error:(FlutterError * _Nullable __autoreleasing * _Nonnull)error {
[TXLiveBase setLogLevel:logLevel.value.intValue];
[FTXLog setLogLevel:logLevel.value.intValue];
}
- (nullable BoolMsg *)startVideoOrientationServiceWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error {
......
// Copyright (c) 2022 Tencent. All rights reserved.
#ifndef SUPERPLAYER_FLUTTER_IOS_CLASSES_TOOLS_FTXLOG_H_
#define SUPERPLAYER_FLUTTER_IOS_CLASSES_TOOLS_FTXLOG_H_
#import <Foundation/Foundation.h>
#import "FTXLiteAVSDKHeader.h"
NS_ASSUME_NONNULL_BEGIN
#define FTXLOGV(fmt, ...) \
[FTXLog logLevel:LOGLEVEL_VERBOSE \
file:__FILE__ \
line:__LINE__ \
function:__FUNCTION__ \
info:[NSString stringWithFormat:fmt, ##__VA_ARGS__]];
#define FTXLOGD(fmt, ...) \
[FTXLog logLevel:LOGLEVEL_DEBUG \
file:__FILE__ \
line:__LINE__ \
function:__FUNCTION__ \
info:[NSString stringWithFormat:fmt, ##__VA_ARGS__]];
#define FTXLOGI(fmt, ...) \
[FTXLog logLevel:LOGLEVEL_INFO \
file:__FILE__ \
line:__LINE__ \
function:__FUNCTION__ \
info:[NSString stringWithFormat:fmt, ##__VA_ARGS__]];
#define FTXLOGW(fmt, ...) \
[FTXLog logLevel:LOGLEVEL_WARN \
file:__FILE__ \
line:__LINE__ \
function:__FUNCTION__ \
info:[NSString stringWithFormat:fmt, ##__VA_ARGS__]];
#define FTXLOGE(fmt, ...) \
[FTXLog logLevel:LOGLEVEL_ERROR \
file:__FILE__ \
line:__LINE__ \
function:__FUNCTION__ \
info:[NSString stringWithFormat:fmt, ##__VA_ARGS__]];
@interface FTXLog : NSObject
/**
* 日志打印
* @param level 方法
* @param file 文件名
* @param line 行
* @param function 方法
* @param info 信息
*/
+ (void)logLevel:(TX_Enum_Type_LogLevel)level
file:(const char *)file
line:(int)line
function:(const char *)function
info:(NSString *)info;
+ (void)setLogLevel:(TX_Enum_Type_LogLevel)level;
@end
NS_ASSUME_NONNULL_END
#endif // SUPERPLAYER_FLUTTER_IOS_CLASSES_TOOLS_FTXLOG_H_
// Copyright (c) 2022 Tencent. All rights reserved.
#import "FTXLog.h"
extern void tpl_log(int level, const char *file, int line, const char *func, const char *format, ...);
static TX_Enum_Type_LogLevel currentLogLevel = LOGLEVEL_VERBOSE;
@implementation FTXLog
+ (void)setLogLevel:(TX_Enum_Type_LogLevel)level {
currentLogLevel = level;
}
+ (void)logLevel:(TX_Enum_Type_LogLevel)level file:(const char *)file line:(int)line function:(const char *)function info:(NSString *)info {
if (level >= currentLogLevel) {
NSString *finalInfoString = [NSString stringWithFormat:@"[FTXPlayerLog] %@", info];
const char *finalInfo = [finalInfoString UTF8String];
[self logL:level
file:file
line:line
function:function
info:finalInfo];
}
}
#pragma mark - private methods
//LOGLEVEL_VERBOSE = 0, // VERBOSE
//LOGLEVEL_DEBUG = 1, // DEBUG
//LOGLEVEL_INFO = 2, // INFO
//LOGLEVEL_WARN = 3, // WARNING
//LOGLEVEL_ERROR = 4, // ERROR
//LOGLEVEL_FATAL = 5, // FATAL
//LOGLEVEL_NULL = 6, // NONE
+ (void)logL:(TX_Enum_Type_LogLevel)level
file:(const char *)file
line:(int)line
function:(const char *)function
info:(const char *)info {
switch (level) {
case LOGLEVEL_VERBOSE:
{
tpl_log(0, file, line, function, info);
}
break;
case LOGLEVEL_DEBUG:
{
tpl_log(1, file, line, function, info);
}
break;
case LOGLEVEL_INFO:
{
tpl_log(2, file, line, function, info);
}
break;
case LOGLEVEL_WARN:
{
tpl_log(3, file, line, function, info);
}
break;
case LOGLEVEL_ERROR:
{
tpl_log(4, file, line, function, info);
}
break;
case LOGLEVEL_FATAL:
{
tpl_log(5, file, line, function, info);
}
break;
case LOGLEVEL_NULL:
{
tpl_log(6, file, line, function, info);
}
break;
default:
break;
}
}
@end
......@@ -173,6 +173,8 @@ abstract class TXVodPlayEvent {
// Video SEI frame information, Player Premium version 11.6 starts to support
// 视频 SEI 帧信息, 播放器高级版 11.6 版本开始支持
static const VOD_PLAY_EVT_VIDEO_SEI = 2030;
// video loop once complete
static const VOD_PLAY_EVT_LOOP_ONCE_COMPLETE = 6001;
// UTC time
// UTC时间
......
......@@ -180,6 +180,10 @@ class SuperPlayerController {
break;
case TXVodPlayEvent.PLAY_EVT_PLAY_END:
_updatePlayerState(SuperPlayerState.END);
// reset start time when end
if (startPos > 0) {
await setStartTime(0);
}
break;
case TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS:
dynamic progress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS];
......@@ -207,11 +211,17 @@ class SuperPlayerController {
currentSubtitleData = new TXVodSubtitleData(subtitleDataStr, startPositionMs, durationMs, trackIndex);
_observer?.onSubtitleData(currentSubtitleData);
break;
case TXVodPlayEvent.VOD_PLAY_EVT_SELECT_TRACK_COMPLETE: {
case TXVodPlayEvent.VOD_PLAY_EVT_SELECT_TRACK_COMPLETE:
int trackIndex = event[TXVodPlayEvent.EVT_KEY_SELECT_TRACK_INDEX];
int errorCode = event[TXVodPlayEvent.EVT_KEY_SELECT_TRACK_ERROR_CODE];
LogUtils.d(TAG, "SELECT_TRACK_COMPLETE trackIndex: ${trackIndex}, errorCode: ${errorCode}");
break;
case TXVodPlayEvent.VOD_PLAY_EVT_LOOP_ONCE_COMPLETE:
// reset start time when once complete
if (startPos > 0) {
await setStartTime(0);
}
break;
}
});
_vodNetEventListener = _vodPlayerController.onPlayerNetStatusBroadcast.listen((event) {
......
......@@ -54,6 +54,10 @@ class TXPipController {
} else if ((Platform.isIOS && eventCode == TXVodPlayEvent.EVENT_IOS_PIP_MODE_WILL_EXIT) ||
(Platform.isAndroid && eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_EXIT)) {
_playerData?.isEnterPip = false;
/**
* if you do not intend to continue reusing this vod player.
* exitAndReleaseCurrentPip must be called, otherwise there may be a obj leak
*/
await exitAndReleaseCurrentPip();
} else if (eventCode == TXVodPlayEvent.EVENT_IOS_PIP_MODE_RESTORE_UI) {
_extParams[ARGUMENT_PIP_START_TIME] = event["playTime"];
......
......@@ -132,7 +132,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
_pipSubscription =
SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
int eventCode = event["event"];
if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_EXIT) {
if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_EXIT
|| eventCode == TXVodPlayEvent.EVENT_IOS_PIP_MODE_RESTORE_UI) {
_isFloatingMode = false;
_playController._updatePlayerUIStatus(_pipPreUiStatus);
} else if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_REQUEST_START) {
......@@ -634,7 +635,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
} else if (result == TXVodPlayEvent.ERROR_PIP_ACTIVITY_DESTROYED) {
failedStr = "enterPip failed,because activity is destroyed";
} else {
failedStr = "enterPip failed,unkonw error";
failedStr = "enterPip failed,unkonw error:$result";
}
LogUtils.e(TAG, failedStr);
}
......
......@@ -20,7 +20,7 @@ dependencies:
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
path: ../../Flutter
dev_dependencies:
flutter_test:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论