Skip to content

Commit 061b2ec

Browse files
authored
[video_player_videohole] Add suspend and restore api for handing onPause and onResume lifecyle event (#858)
1 parent 95fa64f commit 061b2ec

18 files changed

+925
-161
lines changed

packages/video_player_videohole/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.5.6
2+
3+
* Add suspend and restore for handing onPause and onResume lifecycle event.
4+
15
## 0.5.5
26

37
* Update the LICENSE file so that it is recognized by pub.dev.

packages/video_player_videohole/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ To use this package, add `video_player_videohole` as a dependency in your `pubsp
1212

1313
```yaml
1414
dependencies:
15-
video_player_videohole: ^0.5.5
15+
video_player_videohole: ^0.5.6
1616
```
1717
1818
Then you can import `video_player_videohole` in your Dart code:

packages/video_player_videohole/example/lib/main.dart

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:flutter/material.dart';
1212
import 'package:flutter/services.dart';
1313
import 'package:http/http.dart' as http;
1414
import 'package:video_player_videohole/video_player.dart';
15+
import 'package:video_player_videohole/video_player_platform_interface.dart';
1516

1617
void main() {
1718
runApp(MaterialApp(home: _App()));
@@ -21,7 +22,7 @@ class _App extends StatelessWidget {
2122
@override
2223
Widget build(BuildContext context) {
2324
return DefaultTabController(
24-
length: 6,
25+
length: 8,
2526
child: Scaffold(
2627
key: const ValueKey<String>('home_page'),
2728
appBar: AppBar(
@@ -35,6 +36,8 @@ class _App extends StatelessWidget {
3536
Tab(icon: Icon(Icons.cloud), text: 'DRM Widevine'),
3637
Tab(icon: Icon(Icons.cloud), text: 'DRM PlayReady'),
3738
Tab(icon: Icon(Icons.cloud), text: 'Track'),
39+
Tab(icon: Icon(Icons.live_tv), text: 'Live'),
40+
Tab(icon: Icon(Icons.local_florist), text: 'ChangeURLTest'),
3841
],
3942
),
4043
),
@@ -46,6 +49,8 @@ class _App extends StatelessWidget {
4649
_DrmRemoteVideo(),
4750
_DrmRemoteVideo2(),
4851
_TrackTest(),
52+
_LiveRemoteVideo(),
53+
_TestRemoteVideo(),
4954
],
5055
),
5156
),
@@ -684,3 +689,142 @@ class _GetTextTrackButton extends StatelessWidget {
684689
);
685690
}
686691
}
692+
693+
class _LiveRemoteVideo extends StatefulWidget {
694+
@override
695+
State<_LiveRemoteVideo> createState() => _LiveRomoteVideoState();
696+
}
697+
698+
class _LiveRomoteVideoState extends State<_LiveRemoteVideo> {
699+
late VideoPlayerController _controller;
700+
701+
@override
702+
void initState() {
703+
super.initState();
704+
_controller = VideoPlayerController.network(
705+
'https://hlive.ktv.go.kr/live/klive_h.stream/playlist.m3u8',
706+
);
707+
708+
_controller.addListener(() {
709+
if (_controller.value.hasError) {
710+
print(_controller.value.errorDescription);
711+
}
712+
setState(() {});
713+
});
714+
_controller.setLooping(true);
715+
_controller.initialize().then((_) => setState(() {}));
716+
_controller.play();
717+
}
718+
719+
@override
720+
void dispose() {
721+
_controller.dispose();
722+
super.dispose();
723+
}
724+
725+
@override
726+
Widget build(BuildContext context) {
727+
return SingleChildScrollView(
728+
child: Column(
729+
children: <Widget>[
730+
Container(padding: const EdgeInsets.only(top: 20.0)),
731+
const Text('Playing Live TV'),
732+
Container(
733+
padding: const EdgeInsets.all(20),
734+
child: AspectRatio(
735+
aspectRatio: _controller.value.aspectRatio,
736+
child: Stack(
737+
alignment: Alignment.bottomCenter,
738+
children: <Widget>[
739+
VideoPlayer(_controller),
740+
ClosedCaption(text: _controller.value.caption.text),
741+
_ControlsOverlay(controller: _controller),
742+
VideoProgressIndicator(_controller, allowScrubbing: true),
743+
],
744+
),
745+
),
746+
),
747+
],
748+
),
749+
);
750+
}
751+
}
752+
753+
class _TestRemoteVideo extends StatefulWidget {
754+
@override
755+
State<_TestRemoteVideo> createState() => _TestRemoteVideoState();
756+
}
757+
758+
class _TestRemoteVideoState extends State<_TestRemoteVideo> {
759+
late VideoPlayerController _controller;
760+
761+
@override
762+
void initState() {
763+
super.initState();
764+
_controller = VideoPlayerController.network(
765+
'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8',
766+
);
767+
768+
_controller.addListener(() {
769+
if (_controller.value.hasError) {
770+
print(_controller.value.errorDescription);
771+
}
772+
setState(() {});
773+
});
774+
_controller.setLooping(true);
775+
_controller.initialize().then((_) => setState(() {}));
776+
_controller.play();
777+
_controller.setRestoreData(
778+
restoreDataSource: restoreDataSource,
779+
resumeTime: restoreTime,
780+
);
781+
}
782+
783+
@override
784+
void dispose() {
785+
_controller.dispose();
786+
super.dispose();
787+
}
788+
789+
DataSource restoreDataSource() {
790+
final DataSource dataSource = DataSource(
791+
sourceType: DataSourceType.network,
792+
uri: 'https://media.w3.org/2010/05/bunny/trailer.mp4',
793+
);
794+
return dataSource;
795+
}
796+
797+
int restoreTime() {
798+
/// if resumeTime >= 0 , it will restore from resumeTime
799+
/// if resumeTime is not set or <0, it will restore from the time when suspend is called
800+
const int resumeTime = 0;
801+
return resumeTime;
802+
}
803+
804+
@override
805+
Widget build(BuildContext context) {
806+
return SingleChildScrollView(
807+
child: Column(
808+
children: <Widget>[
809+
Container(padding: const EdgeInsets.only(top: 20.0)),
810+
const Text('ChangeURLTest'),
811+
Container(
812+
padding: const EdgeInsets.all(20),
813+
child: AspectRatio(
814+
aspectRatio: _controller.value.aspectRatio,
815+
child: Stack(
816+
alignment: Alignment.bottomCenter,
817+
children: <Widget>[
818+
VideoPlayer(_controller),
819+
ClosedCaption(text: _controller.value.caption.text),
820+
_ControlsOverlay(controller: _controller),
821+
VideoProgressIndicator(_controller, allowScrubbing: true),
822+
],
823+
),
824+
),
825+
),
826+
],
827+
),
828+
);
829+
}
830+
}

packages/video_player_videohole/lib/src/messages.g.dart

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -301,39 +301,42 @@ class _VideoPlayerVideoholeApiCodec extends StandardMessageCodec {
301301
if (value is CreateMessage) {
302302
buffer.putUint8(128);
303303
writeValue(buffer, value.encode());
304-
} else if (value is DurationMessage) {
304+
} else if (value is CreateMessage) {
305305
buffer.putUint8(129);
306306
writeValue(buffer, value.encode());
307-
} else if (value is GeometryMessage) {
307+
} else if (value is DurationMessage) {
308308
buffer.putUint8(130);
309309
writeValue(buffer, value.encode());
310-
} else if (value is LoopingMessage) {
310+
} else if (value is GeometryMessage) {
311311
buffer.putUint8(131);
312312
writeValue(buffer, value.encode());
313-
} else if (value is MixWithOthersMessage) {
313+
} else if (value is LoopingMessage) {
314314
buffer.putUint8(132);
315315
writeValue(buffer, value.encode());
316-
} else if (value is PlaybackSpeedMessage) {
316+
} else if (value is MixWithOthersMessage) {
317317
buffer.putUint8(133);
318318
writeValue(buffer, value.encode());
319-
} else if (value is PlayerMessage) {
319+
} else if (value is PlaybackSpeedMessage) {
320320
buffer.putUint8(134);
321321
writeValue(buffer, value.encode());
322-
} else if (value is PositionMessage) {
322+
} else if (value is PlayerMessage) {
323323
buffer.putUint8(135);
324324
writeValue(buffer, value.encode());
325-
} else if (value is SelectedTracksMessage) {
325+
} else if (value is PositionMessage) {
326326
buffer.putUint8(136);
327327
writeValue(buffer, value.encode());
328-
} else if (value is TrackMessage) {
328+
} else if (value is SelectedTracksMessage) {
329329
buffer.putUint8(137);
330330
writeValue(buffer, value.encode());
331-
} else if (value is TrackTypeMessage) {
331+
} else if (value is TrackMessage) {
332332
buffer.putUint8(138);
333333
writeValue(buffer, value.encode());
334-
} else if (value is VolumeMessage) {
334+
} else if (value is TrackTypeMessage) {
335335
buffer.putUint8(139);
336336
writeValue(buffer, value.encode());
337+
} else if (value is VolumeMessage) {
338+
buffer.putUint8(140);
339+
writeValue(buffer, value.encode());
337340
} else {
338341
super.writeValue(buffer, value);
339342
}
@@ -345,26 +348,28 @@ class _VideoPlayerVideoholeApiCodec extends StandardMessageCodec {
345348
case 128:
346349
return CreateMessage.decode(readValue(buffer)!);
347350
case 129:
348-
return DurationMessage.decode(readValue(buffer)!);
351+
return CreateMessage.decode(readValue(buffer)!);
349352
case 130:
350-
return GeometryMessage.decode(readValue(buffer)!);
353+
return DurationMessage.decode(readValue(buffer)!);
351354
case 131:
352-
return LoopingMessage.decode(readValue(buffer)!);
355+
return GeometryMessage.decode(readValue(buffer)!);
353356
case 132:
354-
return MixWithOthersMessage.decode(readValue(buffer)!);
357+
return LoopingMessage.decode(readValue(buffer)!);
355358
case 133:
356-
return PlaybackSpeedMessage.decode(readValue(buffer)!);
359+
return MixWithOthersMessage.decode(readValue(buffer)!);
357360
case 134:
358-
return PlayerMessage.decode(readValue(buffer)!);
361+
return PlaybackSpeedMessage.decode(readValue(buffer)!);
359362
case 135:
360-
return PositionMessage.decode(readValue(buffer)!);
363+
return PlayerMessage.decode(readValue(buffer)!);
361364
case 136:
362-
return SelectedTracksMessage.decode(readValue(buffer)!);
365+
return PositionMessage.decode(readValue(buffer)!);
363366
case 137:
364-
return TrackMessage.decode(readValue(buffer)!);
367+
return SelectedTracksMessage.decode(readValue(buffer)!);
365368
case 138:
366-
return TrackTypeMessage.decode(readValue(buffer)!);
369+
return TrackMessage.decode(readValue(buffer)!);
367370
case 139:
371+
return TrackTypeMessage.decode(readValue(buffer)!);
372+
case 140:
368373
return VolumeMessage.decode(readValue(buffer)!);
369374
default:
370375
return super.readValueOfType(type, buffer);
@@ -823,4 +828,57 @@ class VideoPlayerVideoholeApi {
823828
return (replyList[0] as DurationMessage?)!;
824829
}
825830
}
831+
832+
Future<void> suspend(int arg_playerId) async {
833+
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
834+
'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.suspend',
835+
codec,
836+
binaryMessenger: _binaryMessenger,
837+
);
838+
final List<Object?>? replyList =
839+
await channel.send(<Object?>[arg_playerId]) as List<Object?>?;
840+
if (replyList == null) {
841+
throw PlatformException(
842+
code: 'channel-error',
843+
message: 'Unable to establish connection on channel.',
844+
);
845+
} else if (replyList.length > 1) {
846+
throw PlatformException(
847+
code: replyList[0]! as String,
848+
message: replyList[1] as String?,
849+
details: replyList[2],
850+
);
851+
} else {
852+
return;
853+
}
854+
}
855+
856+
Future<void> restore(
857+
int arg_playerId,
858+
CreateMessage? arg_msg,
859+
int arg_resumeTime,
860+
) async {
861+
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
862+
'dev.flutter.pigeon.video_player_videohole.VideoPlayerVideoholeApi.restore',
863+
codec,
864+
binaryMessenger: _binaryMessenger,
865+
);
866+
final List<Object?>? replyList =
867+
await channel.send(<Object?>[arg_playerId, arg_msg, arg_resumeTime])
868+
as List<Object?>?;
869+
if (replyList == null) {
870+
throw PlatformException(
871+
code: 'channel-error',
872+
message: 'Unable to establish connection on channel.',
873+
);
874+
} else if (replyList.length > 1) {
875+
throw PlatformException(
876+
code: replyList[0]! as String,
877+
message: replyList[1] as String?,
878+
details: replyList[2],
879+
);
880+
} else {
881+
return;
882+
}
883+
}
826884
}

0 commit comments

Comments
 (0)