Skip to content

Commit 35ffe79

Browse files
improved vlc controller events & callbacks code (#216)
* updated vlc event handling code * fix vlc error description * renamed error const strings * fixed a minor bug * Avoid FlutterVlcPlayerFactory new instances onAttachedToActivity (#214) * Avoid FlutterVlcPlayerFactory new instances onAttachedToActivity * Avoid FlutterVlcPlayerFactory instances in registerWith * fix error description docs * Added onInit & onRenderer listeners * updated docs mark onInit & onRendererHandler as deprecated. * updated documentation * fix initialization value of renderer variables Co-authored-by: Guillermo Jeremy De La Cruz Onton <[email protected]>
1 parent 8f795d3 commit 35ffe79

File tree

8 files changed

+121
-58
lines changed

8 files changed

+121
-58
lines changed

flutter_vlc_player/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 6.0.2
2+
* Fix issue with vlc error event
3+
* Added onInit & onRenderer listeners
4+
Credits to Alireza Setayesh (https://github.com/alr2413) and solid-vovabeloded (https://github.com/solid-vovabeloded).
5+
16
## 6.0.1
27
* Fix issue with black screen / offstage
38
Credits to Mitch Ross (https://github.com/mitchross)

flutter_vlc_player/android/src/main/java/software/solid/fluttervlcplayer/FlutterVlcPlayer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ final class FlutterVlcPlayer implements PlatformView {
5050
//
5151
private LibVLC libVLC;
5252
private MediaPlayer mediaPlayer;
53-
private List<RendererDiscoverer> rendererDiscoverers;
54-
private List<RendererItem> rendererItems;
53+
private List<RendererDiscoverer> rendererDiscoverers = new ArrayList<>();;
54+
private List<RendererItem> rendererItems = new ArrayList<>();;
5555
private boolean isDisposed = false;
5656

5757
// Platform view

flutter_vlc_player/example/lib/controls_overlay.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class ControlsOverlay extends StatelessWidget {
2222
reverseDuration: Duration(milliseconds: 200),
2323
child: Builder(
2424
builder: (ctx) {
25-
if (controller.value.isEnded) {
25+
if (controller.value.isEnded || controller.value.hasError) {
2626
return Center(
2727
child: FittedBox(
2828
child: IconButton(

flutter_vlc_player/example/lib/multiple_tab.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class _MultipleTabState extends State<MultipleTab> {
2828
urls[i],
2929
hwAcc: HwAcc.FULL,
3030
autoPlay: false,
31-
onInit: () async {},
3231
options: VlcPlayerOptions(
3332
advanced: VlcAdvancedOptions([
3433
VlcAdvancedOptions.networkCaching(2000),

flutter_vlc_player/example/lib/single_tab.dart

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,6 @@ class _SingleTabState extends State<SingleTab> {
8282
_controller = VlcPlayerController.network(
8383
initVideo.path,
8484
hwAcc: HwAcc.FULL,
85-
onInit: () async {
86-
await _controller.startRendererScanning();
87-
},
88-
onRendererHandler: (type, id, name) {
89-
print('onRendererHandler $type $id $name');
90-
},
9185
options: VlcPlayerOptions(
9286
advanced: VlcAdvancedOptions([
9387
VlcAdvancedOptions.networkCaching(2000),
@@ -110,27 +104,21 @@ class _SingleTabState extends State<SingleTab> {
110104
var file = File(initVideo.path);
111105
_controller = VlcPlayerController.file(
112106
file,
113-
onInit: () async {
114-
await _controller.startRendererScanning();
115-
},
116-
onRendererHandler: (type, id, name) {
117-
print('onRendererHandler $type $id $name');
118-
},
119107
);
120108
break;
121109
case VideoType.asset:
122110
_controller = VlcPlayerController.asset(
123111
initVideo.path,
124-
onInit: () async {
125-
await _controller.startRendererScanning();
126-
},
127-
onRendererHandler: (type, id, name) {
128-
print('onRendererHandler $type $id $name');
129-
},
130112
options: VlcPlayerOptions(),
131113
);
132114
break;
133115
}
116+
_controller.addOnInitListener(() async {
117+
await _controller.startRendererScanning();
118+
});
119+
_controller.addOnRendererEventListener((type, id, name) {
120+
print('OnRendererEventListener $type $id $name');
121+
});
134122
}
135123

136124
@override
@@ -186,8 +174,10 @@ class _SingleTabState extends State<SingleTab> {
186174
onTap: () async {
187175
switch (video.type) {
188176
case VideoType.network:
189-
await _controller.setMediaFromNetwork(video.path,
190-
hwAcc: HwAcc.FULL);
177+
await _controller.setMediaFromNetwork(
178+
video.path,
179+
hwAcc: HwAcc.FULL,
180+
);
191181
break;
192182
case VideoType.file:
193183
ScaffoldMessenger.of(context).showSnackBar(

flutter_vlc_player/lib/src/vlc_player_controller.dart

Lines changed: 91 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
3535
this.hwAcc = HwAcc.AUTO,
3636
this.autoPlay = true,
3737
this.options,
38-
VoidCallback? onInit,
39-
RendererCallback? onRendererHandler,
38+
@Deprecated('Please, use the addOnInitListener method instead.')
39+
VoidCallback? onInit,
40+
@Deprecated('Please, use the addOnRendererEventListener method instead.')
41+
RendererCallback? onRendererHandler,
4042
}) : _dataSourceType = DataSourceType.asset,
4143
_onInit = onInit,
4244
_onRendererHandler = onRendererHandler,
@@ -53,8 +55,10 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
5355
this.hwAcc = HwAcc.AUTO,
5456
this.autoPlay = true,
5557
this.options,
56-
VoidCallback? onInit,
57-
RendererCallback? onRendererHandler,
58+
@Deprecated('Please, use the addOnInitListener method instead.')
59+
VoidCallback? onInit,
60+
@Deprecated('Please, use the addOnRendererEventListener method instead.')
61+
RendererCallback? onRendererHandler,
5862
}) : package = null,
5963
_dataSourceType = DataSourceType.network,
6064
_onInit = onInit,
@@ -71,8 +75,10 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
7175
this.hwAcc = HwAcc.AUTO,
7276
this.autoPlay = true,
7377
this.options,
74-
VoidCallback? onInit,
75-
RendererCallback? onRendererHandler,
78+
@Deprecated('Please, use the addOnInitListener method instead.')
79+
VoidCallback? onInit,
80+
@Deprecated('Please, use the addOnRendererEventListener method instead.')
81+
RendererCallback? onRendererHandler,
7682
}) : dataSource = 'file://${file.path}',
7783
package = null,
7884
_dataSourceType = DataSourceType.file,
@@ -97,6 +103,19 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
97103
/// Initialize vlc player when the platform is ready automatically
98104
final bool autoInitialize;
99105

106+
/// This is a callback that will be executed once the platform view has been initialized.
107+
/// If you want the media to play as soon as the platform view has initialized, you could just call
108+
/// [VlcPlayerController.play] in this callback. (see the example).
109+
///
110+
/// This member is deprecated, please, use the [addOnInitListener] method instead.
111+
final VoidCallback? _onInit;
112+
113+
/// This is a callback that will be executed every time a new renderer cast device attached/detached
114+
/// It should be defined as "void Function(VlcRendererEventType, String, String)", where the VlcRendererEventType is an enum { attached, detached } and the next two String arguments are unique-id and name of renderer device, respectively.
115+
///
116+
/// This member is deprecated, please, use the [addOnRendererEventListener] method instead.
117+
final RendererCallback? _onRendererHandler;
118+
100119
/// Only set for [asset] videos. The package that the asset was loaded from.
101120
String? package;
102121

@@ -117,19 +136,36 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
117136
/// The viewId for this controller
118137
late int _viewId;
119138

120-
/// This is a callback that will be executed once the platform view has been initialized.
121-
/// If you want the media to play as soon as the platform view has initialized, you could just call
122-
/// [VlcPlayerController.play] in this callback. (see the example)
123-
final _onInit;
139+
/// List of onInit listeners
140+
final List<VoidCallback> _onInitListeners = [];
124141

125-
/// This is a callback that will be executed every time a new renderer cast device attached/detached
126-
/// It should be defined as "void Function(VlcRendererEventType, String, String)", where the VlcRendererEventType is an enum { attached, detached } and the next two String arguments are unique-id and name of renderer device, respectively.
127-
final _onRendererHandler;
142+
/// List of onRenderer listeners
143+
final List<RendererCallback> _onRendererEventListeners = [];
128144

129145
bool _isDisposed = false;
130146

131147
VlcAppLifeCycleObserver? _lifeCycleObserver;
132148

149+
/// Register a [VoidCallback] closure to be called when the controller gets initialized
150+
void addOnInitListener(VoidCallback listener) {
151+
_onInitListeners.add(listener);
152+
}
153+
154+
/// Remove a previously registered closure from the list of onInit closures
155+
void removeOnInitListener(VoidCallback listener) {
156+
_onInitListeners.remove(listener);
157+
}
158+
159+
/// Register a [RendererCallback] closure to be called when a cast renderer device gets attached/detached
160+
void addOnRendererEventListener(RendererCallback listener) {
161+
_onRendererEventListeners.add(listener);
162+
}
163+
164+
/// Remove a previously registered closure from the list of OnRendererEvent closures
165+
void removeOnRendererEventListener(RendererCallback listener) {
166+
_onRendererEventListeners.remove(listener);
167+
}
168+
133169
/// Attempts to open the given [url] and load metadata about the video.
134170
Future<void> initialize() async {
135171
if (_isDisposed) {
@@ -168,6 +204,7 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
168204
isBuffering: true,
169205
isEnded: false,
170206
playingState: PlayingState.buffering,
207+
errorDescription: VlcPlayerValue.noError,
171208
);
172209
break;
173210

@@ -201,6 +238,7 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
201238
activeAudioTrack: event.activeAudioTrack,
202239
spuTracksCount: event.spuTracksCount,
203240
activeSpuTrack: event.activeSpuTrack,
241+
errorDescription: VlcPlayerValue.noError,
204242
);
205243
break;
206244

@@ -218,6 +256,7 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
218256
case VlcMediaEventType.timeChanged:
219257
value = value.copyWith(
220258
isEnded: false,
259+
isBuffering: event.mediaEventType == VlcMediaEventType.buffering,
221260
position: event.position,
222261
duration: event.duration,
223262
playbackSpeed: event.playbackSpeed,
@@ -231,6 +270,7 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
231270
playingState: (event.isPlaying ?? false)
232271
? PlayingState.playing
233272
: value.playingState,
273+
errorDescription: VlcPlayerValue.noError,
234274
);
235275
break;
236276

@@ -243,6 +283,7 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
243283
isBuffering: false,
244284
isEnded: false,
245285
playingState: PlayingState.error,
286+
errorDescription: VlcPlayerValue.unknownError,
246287
);
247288
break;
248289

@@ -270,16 +311,12 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
270311
}
271312
switch (event.eventType) {
272313
case VlcRendererEventType.attached:
273-
if (_onRendererHandler != null) {
274-
_onRendererHandler(VlcRendererEventType.attached, event.rendererId,
275-
event.rendererName);
276-
}
277-
break;
278314
case VlcRendererEventType.detached:
279-
if (_onRendererHandler != null) {
280-
_onRendererHandler(VlcRendererEventType.detached, event.rendererId,
281-
event.rendererName);
282-
}
315+
_notifyOnRendererListeners(
316+
event.eventType,
317+
event.rendererId,
318+
event.rendererName,
319+
);
283320
break;
284321
case VlcRendererEventType.unknown:
285322
break;
@@ -297,24 +334,46 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
297334
playingState: PlayingState.initialized,
298335
);
299336

300-
if (_onInit != null) _onInit();
337+
_notifyOnInitListeners();
301338

302339
return initializingCompleter.future;
303340
}
304341

342+
/// Dispose controller
305343
@override
306344
Future<void> dispose() async {
307345
if (_isDisposed) {
308346
return;
309347
}
348+
_onInitListeners.clear();
349+
_onRendererEventListeners.clear();
310350
_lifeCycleObserver?.dispose();
311351
_isDisposed = true;
312352
super.dispose();
313353
//
314-
315354
await vlcPlayerPlatform.dispose(_viewId);
316355
}
317356

357+
/// Notify onInit callback & all registered listeners
358+
void _notifyOnInitListeners() {
359+
if (_onInit != null) {
360+
_onInit!();
361+
}
362+
_onInitListeners.forEach((listener) => listener());
363+
}
364+
365+
/// Notify onRendererHandler callback & all registered listeners
366+
void _notifyOnRendererListeners(
367+
VlcRendererEventType type,
368+
String? id,
369+
String? name,
370+
) {
371+
if (_onRendererHandler != null) {
372+
_onRendererHandler!(type, id!, name!);
373+
}
374+
_onRendererEventListeners.forEach((listener) => listener(type, id!, name!));
375+
}
376+
318377
/// This stops playback and changes the data source. Once the new data source has been loaded, the playback state will revert to
319378
/// its state before the method was called. (i.e. if this method is called whilst media is playing, once the new
320379
/// data source has been loaded, the new stream will begin playing.)
@@ -799,18 +858,24 @@ class VlcPlayerController extends ValueNotifier<VlcPlayerValue> {
799858
return await vlcPlayerPlatform.takeSnapshot(_viewId);
800859
}
801860

861+
/// Get list of available renderer services which is supported by vlc library
862+
Future<List<String>> getAvailableRendererServices() async {
863+
_throwIfNotInitialized('getAvailableRendererServices');
864+
return await vlcPlayerPlatform.getAvailableRendererServices(_viewId);
865+
}
866+
802867
/// Start vlc cast discovery to find external display devices (chromecast)
803868
/// By setting serviceName, the vlc discovers renderer with that service
804869
Future<void> startRendererScanning({String? rendererService}) async {
805870
_throwIfNotInitialized('startRendererScanning');
806-
return await vlcPlayerPlatform.startRendererScanning(viewId!,
871+
return await vlcPlayerPlatform.startRendererScanning(_viewId,
807872
rendererService: rendererService ?? '');
808873
}
809874

810875
/// Stop vlc cast and scan
811876
Future<void> stopRendererScanning() async {
812877
_throwIfNotInitialized('stopRendererScanning');
813-
return await vlcPlayerPlatform.stopRendererScanning(viewId!);
878+
return await vlcPlayerPlatform.stopRendererScanning(_viewId);
814879
}
815880

816881
/// Returns all detected renderer devices as array of <String, String>

flutter_vlc_player/lib/src/vlc_player_value.dart

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import 'enums/playing_state.dart';
77
/// The duration, current position, buffering state, error state and settings
88
/// of a [VlcPlayerController].
99
class VlcPlayerValue {
10+
/// Define no error string
11+
static const String noError = '';
12+
static const String unknownError = 'An Unknown Error Occurred!';
13+
1014
/// Constructs a video with the given values. Only [duration] is required. The
1115
/// rest will initialize with default values when unset.
1216
VlcPlayerValue({
@@ -31,7 +35,7 @@ class VlcPlayerValue {
3135
this.spuDelay = 0,
3236
this.videoTracksCount = 1,
3337
this.activeVideoTrack = 0,
34-
this.errorDescription,
38+
this.errorDescription = VlcPlayerValue.noError,
3539
});
3640

3741
/// Returns an instance with a `null` [Duration].
@@ -49,7 +53,7 @@ class VlcPlayerValue {
4953
duration: Duration.zero,
5054
playingState: PlayingState.error,
5155
isInitialized: false,
52-
errorDescription: errorDescription,
56+
errorDescription: errorDescription ?? VlcPlayerValue.unknownError,
5357
);
5458
}
5559

@@ -114,8 +118,8 @@ class VlcPlayerValue {
114118

115119
/// A description of the error if present.
116120
///
117-
/// If [hasError] is false this is [null].
118-
final String? errorDescription;
121+
/// If [hasError] is false this is [VlcPlayerValue.noError].
122+
final String errorDescription;
119123

120124
/// The [size] of the currently loaded video.
121125
///
@@ -127,7 +131,7 @@ class VlcPlayerValue {
127131

128132
/// Indicates whether or not the video is in an error state. If this is true
129133
/// [errorDescription] should have information about the problem.
130-
bool get hasError => errorDescription != null;
134+
bool get hasError => errorDescription != VlcPlayerValue.noError;
131135

132136
/// Returns [size.width] / [size.height] when the player is initialized, or `1.0.` when
133137
/// the player is not initialized or the aspect ratio would be less than or equal to 0.0.

0 commit comments

Comments
 (0)