提交 613b1868 authored 作者: dokieyang's avatar dokieyang

fix pip bug

上级 e4a3ab95
#### Version: 1.0.2 当前最新版本
##### 分支描述:
main 分支:Android & iOS 端集成TXLiteAVSDK_Player lastest版本
Professional 分支:Android & iOS 端集成TXLiteAVSDK_Professional lastest版本
##### 版本特性:
- Android 端新增画中画(PIP) 功能
- 播放器组件(superplayer)用Dart重写,方便自定义集成
- 修复通过appId 、fileId和 psign 播放失败问题
......@@ -193,7 +193,7 @@ public class FTXPIPManager {
backData.putInt(FTXEvent.EXTRA_NAME_PLAYER_ID, params.mCurrentPlayerId);
Intent backIntent = new Intent(FTXEvent.ACTION_PIP_PLAY_CONTROL).putExtras(backData);
PendingIntent preIntent = PendingIntent.getBroadcast(mActivity, FTXEvent.EXTRA_PIP_PLAY_BACK, backIntent,
PendingIntent.FLAG_IMMUTABLE);
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
RemoteAction preAction = new RemoteAction(getBackIcon(params), "skipPre", "skip pre", preIntent);
// resume or pause
......@@ -204,7 +204,7 @@ public class FTXPIPManager {
new Intent(FTXEvent.ACTION_PIP_PLAY_CONTROL).putExtras(playOrPauseData);
Icon playIcon = isPlaying ? getPauseIcon(params) : getPlayIcon(params);
PendingIntent playIntent = PendingIntent.getBroadcast(mActivity, FTXEvent.EXTRA_PIP_PLAY_RESUME_OR_PAUSE,
playOrPauseIntent, PendingIntent.FLAG_IMMUTABLE);
playOrPauseIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
RemoteAction playOrPauseAction = new RemoteAction(playIcon, "playOrPause", "play Or Pause", playIntent);
// forward
......@@ -214,7 +214,7 @@ public class FTXPIPManager {
Intent forwardIntent = new Intent(FTXEvent.ACTION_PIP_PLAY_CONTROL).putExtras(forwardData);
PendingIntent nextIntent = PendingIntent.getBroadcast(mActivity, FTXEvent.EXTRA_PIP_PLAY_FORWARD,
forwardIntent,
PendingIntent.FLAG_IMMUTABLE);
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
RemoteAction nextAction = new RemoteAction(getForwardIcon(params), "skipNext", "skip next", nextIntent);
List<RemoteAction> actions = new ArrayList<>();
......
......@@ -458,10 +458,10 @@ SuperPlayerPlugin.setGlobalLicense(licenceUrl, licenceKey);
```dart
_controller.enterPictureInPictureMode(
backIcon: "images/superplayer_ic_vod_play_pre.png",
backIcon: "images/ic_pip_play_replay.png",
playIcon: "images/ic_pip_play_normal.png",
pauseIcon: "images/ic_pip_play_pause.png",
forwardIcon: "images/superplayer_ic_vod_play_next.png");
forwardIcon: "images/ic_pip_play_forward.png");
```
**参数说明**
......
// Copyright (c) 2022 Tencent. All rights reserved.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:super_player/super_player.dart';
......@@ -15,6 +17,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
List<SuperPlayerModel> videoModels = [];
bool _isFullScreen = false;
late SuperPlayerController _controller;
StreamSubscription? simpleEventSubscription;
@override
void initState() {
......@@ -24,7 +27,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
// 如果不配置preferredResolution,则在播放多码率视频的时候优先播放720 * 1280分辨率的码率
config.preferredResolution = 720 * 1280;
_controller.setPlayConfig(config);
_controller.onSimplePlayerEventBroadcast.listen((event) {
simpleEventSubscription = _controller.onSimplePlayerEventBroadcast.listen((event) {
String evtName = event["event"];
if (evtName == SuperPlayerViewEvent.onStartFullScreenPlay) {
} else if (evtName == SuperPlayerViewEvent.onStopFullScreenPlay) {
......@@ -213,6 +216,7 @@ class _DemoSuperplayerState extends State<DemoSuperplayer> {
void dispose() {
// must invoke when page exit.
_controller.releasePlayer();
simpleEventSubscription?.cancel();
// restore page brightness
SuperPlayerPlugin.restorePageBrightness();
super.dispose();
......
......@@ -24,6 +24,9 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
"http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv";
bool _isStop = true;
double _maxLiveProgressTime = 0;
StreamSubscription? playEventSubscription;
StreamSubscription? playNetEventSubscription;
StreamSubscription? playerStateEventSubscription;
GlobalKey<VideoSliderState> progressSliderKey = GlobalKey();
......@@ -32,7 +35,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
_controller = TXLivePlayerController();
_controller.onPlayerEventBroadcast.listen((event) {
playEventSubscription = _controller.onPlayerEventBroadcast.listen((event) {
//订阅事件分发
if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {
_progress = event["EVT_PLAY_PROGRESS"].toDouble();
......@@ -60,7 +63,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
}
});
_controller.onPlayerNetStatusBroadcast.listen((event) {
playNetEventSubscription = _controller.onPlayerNetStatusBroadcast.listen((event) {
double w = (event[TXVodNetEvent.NET_STATUS_VIDEO_WIDTH]).toDouble();
double h = (event[TXVodNetEvent.NET_STATUS_VIDEO_HEIGHT]).toDouble();
......@@ -71,7 +74,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
}
});
_controller.onPlayerState.listen((event) {
playerStateEventSubscription = _controller.onPlayerState.listen((event) {
//订阅状态变化
debugPrint("播放状态 ${event!.name}");
});
......@@ -282,6 +285,9 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
@override
void dispose() {
playerStateEventSubscription?.cancel();
playEventSubscription?.cancel();
playNetEventSubscription?.cancel();
_controller.dispose();
super.dispose();
WidgetsBinding.instance?.removeObserver(this);
......
......@@ -31,6 +31,8 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
double _rate = 1.0;
bool enableHardware = true;
int volume = 80;
StreamSubscription? playEventSubscription;
StreamSubscription? playNetEventSubscription;
GlobalKey<VideoSliderState> progressSliderKey = GlobalKey();
......@@ -42,7 +44,10 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
});
LogUtils.logOpen = true;
_controller.onPlayerEventBroadcast.listen((event) async {
SuperPlayerPlugin.setGlobalMaxCacheSize(200);
SuperPlayerPlugin.setGlobalCacheFolderPath("postfixPath");
playEventSubscription = _controller.onPlayerEventBroadcast.listen((event) async {
//订阅状态变化
if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN ||
event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
......@@ -58,7 +63,7 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
}
});
_controller.onPlayerNetStatusBroadcast.listen((event) async {
playNetEventSubscription = _controller.onPlayerNetStatusBroadcast.listen((event) async {
//订阅状态变化
double w = (event[TXVodNetEvent.NET_STATUS_VIDEO_WIDTH]).toDouble();
double h = (event[TXVodNetEvent.NET_STATUS_VIDEO_HEIGHT]).toDouble();
......@@ -374,6 +379,8 @@ class _DemoTXVodlayerState extends State<DemoTXVodPlayer>
@override
void dispose() {
playNetEventSubscription?.cancel();
playEventSubscription?.cancel();
_controller.dispose();
super.dispose();
WidgetsBinding.instance?.removeObserver(this);
......
......@@ -307,13 +307,17 @@ class SuperPlayerController {
if (query.contains("spfileid") || query.contains("spdrmtype") || query.contains("spappid")) {
LogUtils.d(TAG, "url contains superplay key. $query");
}
query += "spfileid=${videoModel!.videoId!.fileId}" "&spdrmtype=$drmType&spappid=${videoModel!.appId}";
}
}
LogUtils.d(TAG, "play url:$url");
query += "spfileid=${videoModel!.videoId!.fileId}" "&spdrmtype=$drmType&spappid=${videoModel!.appId}";
Uri newUri = Uri(path: url, query: query);
LogUtils.d(TAG, 'playVodURL: newurl = ${Uri.decodeFull(newUri.toString())} ;url= $url');
await _vodPlayerController?.startPlay(Uri.decodeFull(newUri.toString()));
} else {
LogUtils.d(TAG, "playVodURL url:$url");
await _vodPlayerController?.startPlay(url);
}
}
}
/// 暂停视频
/// 涉及到_updatePlayerState相关的方法,不使用异步,避免异步调用导致的playerState更新不及时
......
......@@ -20,6 +20,7 @@ class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
bool _isOpenAccelerate = true;
String _currentRate = "";
Map<String, double> playRateStr = {"1.0x": 1.0, "1.25x": 1.25, "1.5x": 1.5, "2.0x": 2.0};
StreamSubscription? volumeSubscription;
@override
void initState() {
......@@ -37,11 +38,13 @@ class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
}
_isOpenAccelerate = widget.controller.getAccelerateIsOpen();
// regist system volume changed event
SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
volumeSubscription = SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
int code = event["event"];
if(mounted) {
if (code == TXVodPlayEvent.EVENT_VOLUME_CHANGED) {
refreshVolume();
}
}
});
_initData();
}
......@@ -239,6 +242,12 @@ class _SuperPlayerMoreViewState extends State<SuperPlayerMoreView> {
});
}
}
@override
void dispose() {
super.dispose();
volumeSubscription?.cancel();
}
}
class _MoreViewController {
......
......@@ -44,6 +44,9 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
late _CoverViewController _coverViewController;
late _MoreViewController _moreViewController;
StreamSubscription? _volumeSubscription;
StreamSubscription? _pipSubscription;
/// init
Timer _controlViewTimer = Timer(Duration(milliseconds: _controlViewShowTime), () {});
......@@ -63,7 +66,6 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
landscapeOrientation = DeviceOrientation.landscapeLeft;
}
_playController = widget._controller;
WidgetsBinding.instance?.addObserver(this);
_fullScreenController = _SuperPlayerFullScreenController(_updateState);
_titleViewController = _VideoTitleController(_onTapBack, () {
_moreViewKey.currentState?.toggleShowMoreView();
......@@ -87,6 +89,37 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
_calculateSize(w, h);
}
});
// only register listen once
_pipSubscription = SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
int eventCode = event["event"];
if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_EXIT) {
// exit floatingMode
Navigator.of(context).pop();
_isFloatingMode = false;
if (_isPlaying) {
// pause play when exit PIP, prevent user just close PIP, but not back to app
_playController._vodPlayerController?.pause();
}
} else if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_REQUEST_START) {
// EVENT_PIP_MODE_ALREADY_ENTER 的状态变化有滞后性,进入PIP之后才会通知,这里需要监听EVENT_PIP_MODE_REQUEST_START,
// 在即将进入PIP模式下就要开始进行PIP模式的UI准备
// enter floatingMode
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SuperPlayerFloatView(_playController, _aspectRatio);
}));
_isFloatingMode = true;
}
});
_volumeSubscription = SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
int eventCode = event["event"];
if (_isFloatingMode && _isPlaying) {
if (eventCode == TXVodPlayEvent.EVENT_AUDIO_FOCUS_PAUSE) {
_onPause();
} else if (eventCode == TXVodPlayEvent.EVENT_AUDIO_FOCUS_PLAY) {
_onResume();
}
}
});
_registerObserver();
_initPlayerState();
}
......@@ -157,36 +190,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
// onDispose
_playController._observer = null; // close observer
});
SuperPlayerPlugin.instance.onExtraEventBroadcast.listen((event) {
int eventCode = event["event"];
if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_ALREADY_EXIT) {
// exit floatingMode
Navigator.of(context).pop();
_isFloatingMode = false;
if (_isPlaying) {
// pause play when exit PIP, prevent user just close PIP, but not back to app
_playController._vodPlayerController?.pause();
}
} else if (eventCode == TXVodPlayEvent.EVENT_PIP_MODE_REQUEST_START) {
// EVENT_PIP_MODE_ALREADY_ENTER 的状态变化有滞后性,进入PIP之后才会通知,这里需要监听EVENT_PIP_MODE_REQUEST_START,
// 在即将进入PIP模式下就要开始进行PIP模式的UI准备
// enter floatingMode
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SuperPlayerFloatView(_playController, _aspectRatio);
}));
_isFloatingMode = true;
}
});
SuperPlayerPlugin.instance.onEventBroadcast.listen((event) {
int eventCode = event["event"];
if (_isFloatingMode && _isPlaying) {
if (eventCode == TXVodPlayEvent.EVENT_AUDIO_FOCUS_PAUSE) {
_onPause();
} else if (eventCode == TXVodPlayEvent.EVENT_AUDIO_FOCUS_PLAY) {
_onResume();
}
}
});
WidgetsBinding.instance?.addObserver(this);
}
void _initPlayerState() {
......@@ -433,10 +437,10 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
void _onEnterPipMode() async {
if (!_isFloatingMode) {
int? result = await _playController.enterPictureInPictureMode(
backIcon: "images/superplayer_ic_vod_play_pre.png",
backIcon: "images/ic_pip_play_replay.png",
playIcon: "images/ic_pip_play_normal.png",
pauseIcon: "images/ic_pip_play_pause.png",
forwardIcon: "images/superplayer_ic_vod_play_next.png");
forwardIcon: "images/ic_pip_play_forward.png");
if (null != result) {
String failedStr = "";
if(result != TXVodPlayEvent.NO_ERROR) {
......@@ -523,6 +527,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SuperPlayerFullScreenView(_playController, _fullScreenController);
}));
WidgetsBinding.instance?.removeObserver(this);
} else {
// exit fullscreen widget
Navigator.of(context).pop();
......@@ -605,6 +610,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
@override
void dispose() {
WidgetsBinding.instance?.removeObserver(this);
_pipSubscription?.cancel();
_volumeSubscription?.cancel();
super.dispose();
}
}
......
......@@ -47,8 +47,8 @@ flutter:
- images/ic_pip_play_icon.png
- images/ic_pip_play_normal.png
- images/ic_pip_play_pause.png
- images/superplayer_ic_vod_play_next.png
- images/superplayer_ic_vod_play_pre.png
- images/ic_pip_play_forward.png
- images/ic_pip_play_replay.png
- images/superplayer_ic_vod_more_normal.png
- images/superplayer_ic_light_max.png
- images/superplayer_ic_light_min.png
......
......@@ -73,7 +73,8 @@ class SuperPlayerPlugin {
return await _channel.invokeMethod('releasePlayer', {"playerId": playerId});
}
/// 设置全局最大缓存文件个数
/// 设置播放引擎的最大缓存大小。设置后会根据设定值自动清理Cache目录的文件
/// @param size 最大缓存大小(单位:MB)
static Future<void> setGlobalMaxCacheSize(int size) async {
return await _channel.invokeMethod('setGlobalMaxCacheSize', {"size": size});
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论