Skip to content

Commit

Permalink
Optimize initilizate time of AgoraVideoView with PlatformView renderi…
Browse files Browse the repository at this point in the history
…ng (#937)

* Optimize initilizate time of AgoraVideoView with PlatformView rendering
  • Loading branch information
littleGnAl committed May 10, 2023
1 parent 64dbc86 commit 4a0feb3
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class JoinChannelVideo extends StatefulWidget {

class _State extends State<JoinChannelVideo> {
late final RtcEngine _engine;
bool _isReadyPreview = false;

bool isJoined = false, switchCamera = true, switchRender = true;
Set<int> remoteUid = {};
Expand Down Expand Up @@ -96,12 +95,6 @@ class _State extends State<JoinChannelVideo> {
bitrate: 0,
),
);

await _engine.startPreview();

setState(() {
_isReadyPreview = true;
});
}

Future<void> _joinChannel() async {
Expand Down Expand Up @@ -131,7 +124,6 @@ class _State extends State<JoinChannelVideo> {
Widget build(BuildContext context) {
return ExampleActionsWidget(
displayContentBuilder: (context, isLayoutHorizontal) {
if (!_isReadyPreview) return Container();
return Stack(
children: [
AgoraVideoView(
Expand All @@ -141,6 +133,9 @@ class _State extends State<JoinChannelVideo> {
useFlutterTexture: _isUseFlutterTexture,
useAndroidSurfaceView: _isUseAndroidSurfaceView,
),
onAgoraVideoViewCreated: (viewId) {
_engine.startPreview();
},
),
Align(
alignment: Alignment.topLeft,
Expand Down
124 changes: 75 additions & 49 deletions lib/src/impl/agora_video_view_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,16 @@ import 'agora_rtc_renderer.dart';

// ignore_for_file: public_member_api_docs

class AgoraVideoViewState extends State<AgoraVideoView> {
AgoraVideoViewState() {
_listener = () {
bool isInitialzed = _controller(widget.controller).isInitialzed;
if (isInitialzed != _isInitialzed) {
setState(() {
_isInitialzed = isInitialzed;
});
}
};
}

late VoidCallback _listener;
late bool _isInitialzed;

VideoViewControllerBaseMixin _controller(VideoViewControllerBase controller) {
return controller as VideoViewControllerBaseMixin;
}

@override
void initState() {
super.initState();

_isInitialzed = _controller(widget.controller).isInitialzed;
_controller(widget.controller).addInitializedCompletedListener(_listener);
}

@override
void didUpdateWidget(covariant AgoraVideoView oldWidget) {
super.didUpdateWidget(oldWidget);

_controller(oldWidget.controller)
.removeInitializedCompletedListener(_listener);
// Refresh the `_isInitialzed` to the current widget.controller `isInitialzed`
_isInitialzed = _controller(widget.controller).isInitialzed;
_controller(widget.controller).addInitializedCompletedListener(_listener);
}
/// Callback when [AgoraVideoView] created.
typedef AgoraVideoViewCreatedCallback = void Function(int viewId);

@override
void deactivate() {
super.deactivate();
_controller(widget.controller)
.removeInitializedCompletedListener(_listener);
}
VideoViewControllerBaseMixin _controller(VideoViewControllerBase controller) {
return controller as VideoViewControllerBaseMixin;
}

class AgoraVideoViewState extends State<AgoraVideoView> {
@override
Widget build(BuildContext context) {
if (!_isInitialzed) {
return Container();
}

if (defaultTargetPlatform == TargetPlatform.macOS ||
defaultTargetPlatform == TargetPlatform.windows) {
return AgoraRtcRenderTexture(
Expand All @@ -75,18 +34,24 @@ class AgoraVideoViewState extends State<AgoraVideoView> {
}

return AgoraRtcRenderPlatformView(
key: widget.key, controller: widget.controller);
key: widget.key,
controller: widget.controller,
onAgoraVideoViewCreated: widget.onAgoraVideoViewCreated,
);
}
}

class AgoraRtcRenderPlatformView extends StatefulWidget {
const AgoraRtcRenderPlatformView({
Key? key,
required this.controller,
this.onAgoraVideoViewCreated,
}) : super(key: key);

final VideoViewControllerBase controller;

final AgoraVideoViewCreatedCallback? onAgoraVideoViewCreated;

@override
State<AgoraRtcRenderPlatformView> createState() =>
_AgoraRtcRenderPlatformViewState();
Expand All @@ -100,6 +65,8 @@ class _AgoraRtcRenderPlatformViewState extends State<AgoraRtcRenderPlatformView>
int _nativeViewIntPtr = 0;
late String _viewType;

VoidCallback? _listener;

@override
void initState() {
super.initState();
Expand All @@ -119,6 +86,16 @@ class _AgoraRtcRenderPlatformViewState extends State<AgoraRtcRenderPlatformView>
widget.controller.initializeRender();
}

@override
void deactivate() {
super.deactivate();
if (_listener != null) {
_controller(widget.controller)
.removeInitializedCompletedListener(_listener!);
_listener = null;
}
}

@override
void dispose() {
_disposeRender();
Expand Down Expand Up @@ -150,11 +127,32 @@ class _AgoraRtcRenderPlatformViewState extends State<AgoraRtcRenderPlatformView>
);
}

Future<void> _setupNativeView() async {
if (_nativeViewIntPtr == 0) {
return;
}

await widget.controller.setupView(_nativeViewIntPtr);
widget.onAgoraVideoViewCreated?.call(_nativeViewIntPtr);
}

Future<void> _setupVideo() async {
_nativeViewIntPtr =
(await getMethodChannel()!.invokeMethod<int>('getNativeViewPtr'))!;
if (!mounted) return;
await widget.controller.setupView(_nativeViewIntPtr);
if (!_controller(widget.controller).isInitialzed) {
_listener ??= () {
_controller(widget.controller)
.removeInitializedCompletedListener(_listener!);
_listener = null;

_setupNativeView();
};
_controller(widget.controller)
.addInitializedCompletedListener(_listener!);
} else {
await _setupNativeView();
}
}

Future<void> _disposeRender() async {
Expand All @@ -180,13 +178,31 @@ class _AgoraRtcRenderTextureState extends State<AgoraRtcRenderTexture>
int _width = 0;
int _height = 0;

VoidCallback? _listener;

@override
void initState() {
super.initState();

_initialize();
}

Future<void> _initialize() async {
if (!_controller(widget.controller).isInitialzed) {
_listener ??= () {
_controller(widget.controller)
.removeInitializedCompletedListener(_listener!);
_listener = null;
_initializeTexture();
};
_controller(widget.controller)
.addInitializedCompletedListener(_listener!);
} else {
await _initializeTexture();
}
}

Future<void> _initializeTexture() async {
final oldTextureId = widget.controller.getTextureId();
await widget.controller.initializeRender();
if (oldTextureId != widget.controller.getTextureId()) {
Expand Down Expand Up @@ -216,6 +232,16 @@ class _AgoraRtcRenderTextureState extends State<AgoraRtcRenderTexture>
}
}

@override
void deactivate() {
super.deactivate();
if (_listener != null) {
_controller(widget.controller)
.removeInitializedCompletedListener(_listener!);
_listener = null;
}
}

@override
void dispose() {
widget.controller.disposeRender();
Expand Down
4 changes: 2 additions & 2 deletions lib/src/impl/media_player_controller_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class MediaPlayerControllerImpl
}

@override
Future<void> setupView(int nativeViewPtr) async {
Future<void> setupNativeViewInternal(int nativeViewPtr) async {
return setView(nativeViewPtr);
}

Expand All @@ -371,7 +371,7 @@ class MediaPlayerControllerImpl
}

@override
Future<void> disposeRender() async {
Future<void> disposeRenderInternal() async {
if (shouldUseFlutterTexture) {
await super.disposeRender();
}
Expand Down
40 changes: 34 additions & 6 deletions lib/src/impl/video_view_controller_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ extension VideoViewControllerBaseExt on VideoViewControllerBase {
mixin VideoViewControllerBaseMixin implements VideoViewControllerBase {
int _textureId = kTextureNotInit;

bool _isSetupView = false;
bool _isDisposeRender = false;

@internal
bool get isInitialzed => (rtcEngine as RtcEngineImpl).isInitialzed;

Expand All @@ -69,11 +72,13 @@ mixin VideoViewControllerBaseMixin implements VideoViewControllerBase {
}

@override
Future<void> dispose() async {}
Future<void> dispose() async {
_isDisposeRender = true;
_isSetupView = false;
}

@internal
@override
Future<void> disposeRender() async {
@protected
Future<void> disposeRenderInternal() async {
if (shouldUseFlutterTexture) {
await rtcEngine.globalVideoViewController
.destroyTextureRender(getTextureId());
Expand Down Expand Up @@ -103,6 +108,18 @@ mixin VideoViewControllerBaseMixin implements VideoViewControllerBase {
}
}

@internal
@override
Future<void> disposeRender() async {
if (!_isSetupView) {
return;
}
_isDisposeRender = true;
_isSetupView = false;

await disposeRenderInternal();
}

@protected
@override
Future<int> createTextureRender(
Expand Down Expand Up @@ -130,8 +147,8 @@ mixin VideoViewControllerBaseMixin implements VideoViewControllerBase {
} else {}
}

@override
Future<void> setupView(int nativeViewPtr) async {
@protected
Future<void> setupNativeViewInternal(int nativeViewPtr) async {
VideoCanvas videoCanvas = VideoCanvas(
view: nativeViewPtr,
renderMode: canvas.renderMode,
Expand All @@ -154,6 +171,17 @@ mixin VideoViewControllerBaseMixin implements VideoViewControllerBase {
}
}

@override
Future<void> setupView(int nativeViewPtr) async {
if (_isDisposeRender) {
return;
}

await setupNativeViewInternal(nativeViewPtr);

_isSetupView = true;
}

@internal
bool get shouldHandlerRenderMode => true;
}
9 changes: 8 additions & 1 deletion lib/src/render/agora_video_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@ import '../impl/agora_video_view_impl.dart';
/// The AgoraVideoView Class for rendering local and remote video.
class AgoraVideoView extends StatefulWidget {
/// @nodoc
const AgoraVideoView({Key? key, required this.controller}) : super(key: key);
const AgoraVideoView({
Key? key,
required this.controller,
this.onAgoraVideoViewCreated,
}) : super(key: key);

/// Controls the type of video to render:If you want to render video of the RtcEngine, see VideoViewController .If you want to render video of the media player, see MediaPlayerController .
final VideoViewControllerBase controller;

/// Callback when [AgoraVideoView] created.
final void Function(int viewId)? onAgoraVideoViewCreated;

@override
State<AgoraVideoView> createState() => AgoraVideoViewState();
}

0 comments on commit 4a0feb3

Please sign in to comment.