Skip to content

Commit 85d77e5

Browse files
committed
Mem leak testing
1 parent 6c8a843 commit 85d77e5

File tree

5 files changed

+308
-341
lines changed

5 files changed

+308
-341
lines changed

flutter_theoplayer_sdk/flutter_theoplayer_sdk/example/android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ android {
5454
applicationId "com.theoplayer.theoplayer_example"
5555
// You can update the following values to match your application needs.
5656
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
57-
minSdkVersion 23
57+
minSdkVersion flutter.minSdkVersion
5858
targetSdkVersion flutter.targetSdkVersion
5959
versionCode flutterVersionCode.toInteger()
6060
versionName flutterVersionName
Lines changed: 20 additions & 340 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
1-
import 'package:flutter/foundation.dart';
21
import 'package:flutter/material.dart';
3-
import 'package:theoplayer/theoplayer.dart';
4-
import 'package:theoplayer_example/player_widgets/current_time_widget.dart';
5-
import 'package:theoplayer_example/player_widgets/player_ui_widget.dart';
6-
import 'package:theoplayer_example/player_widgets/texture_widgets/aspect_ratio_chromeless_widget.dart';
7-
import 'package:theoplayer_example/player_widgets/texture_widgets/aspect_ratio_custom_fullscreen_widget.dart';
8-
9-
// use your THEOplayer Flutter license here from https://portal.theoplayer.com
10-
// without a license the player only accepts URLs from 'localhost' or 'theoplayer.com' domains
11-
const PLAYER_LICENSE = "";
2+
import 'package:theoplayer_example/player.dart';
3+
import 'package:theoplayer_example/weather_page.dart';
124

135
void main() {
146
runApp(const MyApp());
@@ -22,347 +14,35 @@ class MyApp extends StatefulWidget {
2214
}
2315

2416
class _MyAppState extends State<MyApp> {
25-
UniqueKey key1 = UniqueKey();
26-
UniqueKey key2 = UniqueKey();
27-
late THEOplayer player;
28-
29-
final _messengerKey = GlobalKey<ScaffoldMessengerState>();
30-
31-
@override
32-
void initState() {
33-
super.initState();
34-
35-
player = THEOplayer(
36-
fullscreenBuilder: (BuildContext context, THEOplayer player) {
37-
// default, chromeless behaviour, same as not specifying a fullscreenBuilder.
38-
// return FullscreenStatefulWidget(theoplayer: player, fullscreenConfig: player.theoPlayerConfig.fullscreenConfig),
39-
40-
// example on how to pass a custom UI with the player
41-
return Scaffold(
42-
body: Stack(
43-
alignment: Alignment.center,
44-
children: [
45-
// for hybrid composition:
46-
//FullscreenStatefulWidget(theoplayer: player, fullscreenConfig: player.theoPlayerConfig.fullscreenConfig),
47-
48-
// for Texture-based composition:
49-
AspectRatioCustomFullscreenWidget(theoplayer: player, fullscreenConfig: player.theoPlayerConfig.fullscreenConfiguration),
50-
PlayerUI(player: player),
51-
],
52-
),
53-
);
54-
},
55-
theoPlayerConfig: THEOplayerConfig(
56-
license: PLAYER_LICENSE,
57-
// Extra THEOlive configuration:
58-
//theolive: TheoLiveConfiguration(externalSessionId: "mySessionID"),
59-
webConfiguration: WebConfig(libraryLocation: "/theoplayer")
60-
),
61-
onCreate: () {
62-
print("main - THEOplayer - onCreate");
63-
player.autoplay = true;
64-
player.allowBackgroundPlayback = true;
65-
player.allowAutomaticPictureInPicture = true;
66-
// print errors
67-
player.addEventListener(PlayerEventTypes.ERROR, (errorEvent) {
68-
var error = errorEvent as ErrorEvent;
69-
_messengerKey.currentState?.showSnackBar(
70-
SnackBar(
71-
duration: const Duration(milliseconds: 6000),
72-
backgroundColor: Colors.red,
73-
content: Text(error.error),
74-
action: SnackBarAction(
75-
label: 'OK',
76-
onPressed: () {
77-
// Code to execute.
78-
},
79-
),
80-
),
81-
);
82-
});
83-
84-
player.addEventListener(PlayerEventTypes.PRESENTATIONMODECHANGE, (pmEvent) {
85-
var pmd = pmEvent as PresentationModeChangeEvent;
86-
print("New presentation mode: ${pmd.presentationMode}");
87-
});
88-
89-
});
90-
}
91-
92-
@override
93-
void dispose() {
94-
player.dispose();
95-
super.dispose();
96-
}
17+
int _selectedIndex = 0;
9718

9819
@override
9920
Widget build(BuildContext context) {
10021
return MaterialApp(
101-
scaffoldMessengerKey: _messengerKey,
10222
home: Scaffold(
10323
appBar: AppBar(
10424
title: const Text('THEOplayer example app'),
10525
),
106-
body: Builder(builder: (context) {
107-
return Center(
108-
child: Column(
109-
children: [
110-
SizedBox(
111-
width: 400,
112-
height: 300,
113-
child: Stack(
114-
alignment: Alignment.center,
115-
children: [
116-
//for hybrid compositon.
117-
// ChromelessPlayerView(player: player),
118-
119-
//for Texture-based composition:
120-
AspectRatioChromelessPlayerView(player: player, continuouslyFollowAspectRatioChanges: true,),
121-
PlayerUI(player: player),
122-
],
123-
),
124-
),
125-
Expanded(
126-
child: ListView(
127-
children: [
128-
Column(
129-
children: [
130-
CurrentTimeWidget(player: player),
131-
const SizedBox(
132-
height: 16,
133-
),
134-
const Text("API calls"),
135-
Row(
136-
mainAxisSize: MainAxisSize.max,
137-
mainAxisAlignment: MainAxisAlignment.center,
138-
children: [
139-
FilledButton(
140-
onPressed: () => {player.play()},
141-
child: const Text("PLAY"),
142-
),
143-
FilledButton(
144-
onPressed: () => {player.pause()},
145-
child: const Text("PAUSE"),
146-
),
147-
],
148-
),
149-
FilledButton(
150-
onPressed: () => {logApiCalls()},
151-
child: const Text("API LOGGER"),
152-
),
153-
FilledButton(
154-
onPressed: () {
155-
player.setPresentationMode(PresentationMode.FULLSCREEN);
156-
},
157-
child: const Text("Open Fullscreen")),
158-
FilledButton(
159-
onPressed: () {
160-
if (kIsWeb) {
161-
player.setPresentationMode(PresentationMode.PIP);
162-
} else {
163-
player.allowAutomaticPictureInPicture = !player.allowAutomaticPictureInPicture;
164-
}
165-
},
166-
child: const Text("Open PiP (web) / Flip automatic PiP mode (native)")),
167-
FilledButton(
168-
onPressed: () {
169-
player.setPresentationMode(PresentationMode.INLINE);
170-
},
171-
child: const Text("INLINE")),
172-
FilledButton(
173-
onPressed: () {
174-
player.getVideoTracks().first.targetQuality = player.getVideoTracks().first.qualities.first;
175-
},
176-
child: const Text("set video target quality")),
177-
Column(
178-
children: [
179-
const Text("Sources"),
180-
FilledButton(
181-
onPressed: () {
182-
_licenseConfigCheckDialog(context);
183-
player.source = SourceDescription(sources: [
184-
TypedSource(
185-
src: "https://cdn.theoplayer.com/video/big_buck_bunny/big_buck_bunny.m3u8",
186-
type: "application/x-mpegurl"
187-
),
188-
]);
189-
},
190-
child: const Text("Basic source"),
191-
),
192-
FilledButton(
193-
onPressed: () {
194-
_licenseConfigCheckDialog(context);
195-
196-
/**
197-
* register for theolive events, if interested
198-
*
199-
*
200-
player.theoLive?.addEventListener(THEOliveApiEventTypes.DISTRIBUTIONLOADSTART, (e) {
201-
print("DISTRIBUTIONLOADSTART");
202-
});
203-
player.theoLive?.addEventListener(THEOliveApiEventTypes.DISTRIBUTIONOFFLINE, (e) {
204-
print("DISTRIBUTIONOFFLINE");
205-
});
206-
player.theoLive?.addEventListener(THEOliveApiEventTypes.ENDPOINTLOADED, (e) {
207-
print("ENDPOINTLOADED");
208-
});
209-
player.theoLive?.addEventListener(THEOliveApiEventTypes.INTENTTOFALLBACK, (e) {
210-
print("INTENTTOFALLBACK");
211-
});
212-
player.theoLive?.addEventListener(THEOliveApiEventTypes.ENTERBADNETWORKMODE, (e) {
213-
print("ENTERBADNETWORKMODE");
214-
});
215-
player.theoLive?.addEventListener(THEOliveApiEventTypes.EXITBADNETWORKMODE, (e) {
216-
print("EXITBADNETWORKMODE");
217-
});
218-
*/
219-
220-
/**
221-
* preload channels for faster startup
222-
*
223-
player.theoLive?.preloadChannels(["38yyniscxeglzr8n0lbku57b0"]);
224-
*/
225-
player.source = SourceDescription(sources: [
226-
TheoLiveSource(src: "38yyniscxeglzr8n0lbku57b0"),
227-
]);
228-
},
229-
child: const Text("THEOlive source"),
230-
),
231-
FilledButton(
232-
onPressed: () {
233-
_licenseConfigCheckDialog(context);
234-
player.source = SourceDescription(sources: [
235-
TypedSource(
236-
src: "https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_sd.mpd",
237-
type: "application/dash+xml",
238-
drm: DRMConfiguration(
239-
widevine: WidevineDRMConfiguration(
240-
licenseAcquisitionURL: "https://proxy.uat.widevine.com/proxy?provider=widevine_test"),
241-
)),
242-
]);
243-
},
244-
child: const Text("Widevine source"),
245-
),
246-
FilledButton(
247-
onPressed: () {
248-
_licenseConfigCheckDialog(context);
249-
player.source = SourceDescription(sources: [
250-
TypedSource(
251-
src: "https://fps.ezdrm.com/demo/video/ezdrm.m3u8",
252-
type: "application/x-mpegurl",
253-
drm: DRMConfiguration(
254-
customIntegrationId: "EzdrmDRMIntegration",
255-
fairplay: FairPlayDRMConfiguration(
256-
licenseAcquisitionURL: "https://fps.ezdrm.com/api/licenses/09cc0377-6dd4-40cb-b09d-b582236e70fe",
257-
certificateURL: "https://fps.ezdrm.com/demo/video/eleisure.cer",
258-
headers: null,
259-
),
260-
)),
261-
]);
262-
},
263-
child: const Text("Fairplay EZDRM source - iOS"),
264-
),
265-
FilledButton(
266-
onPressed: () {
267-
_licenseConfigCheckDialog(context);
268-
player.source = SourceDescription(sources: [
269-
TypedSource(
270-
src:
271-
"https://d2jl6e4h8300i8.cloudfront.net/netflix_meridian/4k-18.5!9/keyos-logo/g180-avc_a2.0-vbr-aac-128k/r30/dash-wv-pr/stream.mpd",
272-
drm: DRMConfiguration(
273-
customIntegrationId: "KeyOSDRMIntegration",
274-
integrationParameters: {
275-
"x-keyos-authorization":
276-
"PEtleU9TQXV0aGVudGljYXRpb25YTUw+PERhdGE+PEdlbmVyYXRpb25UaW1lPjIwMTYtMTEtMTkgMDk6MzQ6MDEuOTkyPC9HZW5lcmF0aW9uVGltZT48RXhwaXJhdGlvblRpbWU+MjAyNi0xMS0xOSAwOTozNDowMS45OTI8L0V4cGlyYXRpb25UaW1lPjxVbmlxdWVJZD4wZmZmMTk3YWQzMzQ0ZTMyOWU0MTA0OTIwMmQ5M2VlYzwvVW5pcXVlSWQ+PFJTQVB1YktleUlkPjdlMTE0MDBjN2RjY2QyOWQwMTc0YzY3NDM5N2Q5OWRkPC9SU0FQdWJLZXlJZD48V2lkZXZpbmVQb2xpY3kgZmxfQ2FuUGxheT0idHJ1ZSIgZmxfQ2FuUGVyc2lzdD0iZmFsc2UiIC8+PFdpZGV2aW5lQ29udGVudEtleVNwZWMgVHJhY2tUeXBlPSJIRCI+PFNlY3VyaXR5TGV2ZWw+MTwvU2VjdXJpdHlMZXZlbD48L1dpZGV2aW5lQ29udGVudEtleVNwZWM+PEZhaXJQbGF5UG9saWN5IC8+PExpY2Vuc2UgdHlwZT0ic2ltcGxlIiAvPjwvRGF0YT48U2lnbmF0dXJlPk1sNnhkcU5xc1VNalNuMDdicU8wME15bHhVZUZpeERXSHB5WjhLWElBYlAwOE9nN3dnRUFvMTlYK1c3MDJOdytRdmEzNFR0eDQydTlDUlJPU1NnREQzZTM4aXE1RHREcW9HelcwS2w2a0JLTWxHejhZZGRZOWhNWmpPTGJkNFVkRnJUbmxxU21raC9CWnNjSFljSmdaUm5DcUZIbGI1Y0p0cDU1QjN4QmtxMUREZUEydnJUNEVVcVJiM3YyV1NueUhGeVZqWDhCR3o0ZWFwZmVFeDlxSitKbWI3dUt3VjNqVXN2Y0Fab1ozSHh4QzU3WTlySzRqdk9Wc1I0QUd6UDlCc3pYSXhKd1ZSZEk3RXRoMjhZNXVEQUVZVi9hZXRxdWZiSXIrNVZOaE9yQ2JIVjhrR2praDhHRE43dC9nYWh6OWhVeUdOaXRqY2NCekJvZHRnaXdSUT09PC9TaWduYXR1cmU+PC9LZXlPU0F1dGhlbnRpY2F0aW9uWE1MPg==",
277-
},
278-
widevine: WidevineDRMConfiguration(
279-
licenseAcquisitionURL: "https://wv-keyos.licensekeyserver.com",
280-
),
281-
)),
282-
]);
283-
},
284-
child: const Text("Widevine KeyOS source - Android"),
285-
),
286-
],
287-
)
288-
],
289-
),
290-
],
291-
),
292-
)
293-
],
294-
),
295-
);
296-
}),
297-
),
298-
);
299-
}
300-
301-
Future<void> logApiCalls() async {
302-
print("source: ${player.source}");
303-
print("isAutoplay: ${player.isAutoplay}");
304-
print("isPaused: ${player.isPaused}");
305-
print("currentTime: ${player.currentTime}");
306-
print("currentProgramDateTIme: ${player.currentProgramDateTime}");
307-
print("duration: ${player.duration}");
308-
print("playbackRate: ${player.playbackRate}");
309-
print("volume: ${player.volume}");
310-
print("isMuted: ${player.isMuted}");
311-
print("preload: ${player.preload}");
312-
print("readyState: ${player.readyState}");
313-
print("isSeeking: ${player.isSeeking}");
314-
print("isEnded: ${player.isEnded}");
315-
print("videoHeight: ${player.videoHeight}");
316-
print("videoWidth: ${player.videoWidth}");
317-
print("buffered: ${player.buffered}");
318-
print("seekable: ${player.seekable}");
319-
print("played: ${(player.played)}");
320-
print("error: ${player.error}");
321-
print("audio target quality: ${player.audioTracks.first.targetQuality?.uid}");
322-
print("audio active quality: ${player.audioTracks.first.activeQuality?.uid}");
323-
print("video target quality: ${player.videoTracks.first.targetQuality?.uid}");
324-
print("video active quality: ${player.videoTracks.first.activeQuality?.uid}");
325-
print("allowBackgroundPlayback: ${player.allowBackgroundPlayback}");
326-
327-
if (kIsWeb) {
328-
print("theolive distributionState: ${player.theoLive?.distributionState}");
329-
print("theolive badnetwork: ${player.theoLive?.badNetworkMode}");
330-
}
331-
}
332-
333-
Future<void> _licenseConfigCheckDialog(BuildContext context) async {
334-
if (PLAYER_LICENSE != "") {
335-
//ok
336-
return;
337-
}
338-
339-
return showDialog<void>(
340-
context: context,
341-
barrierDismissible: false, // user must tap button!
342-
builder: (BuildContext context) {
343-
return AlertDialog(
344-
title: const Text('License configuration needed!'),
345-
content: const SingleChildScrollView(
346-
child: ListBody(
347-
children: <Widget>[
348-
Text('Your forgot to configure your license!'),
349-
SizedBox(height: 8,),
350-
Text('Without a license, THEOplayer can only play sources from `theoplayer.com`'),
351-
SizedBox(height: 8,),
352-
Text('Get your license from `https://portal.theoplayer.com!`'),
353-
],
26+
body: _selectedIndex == 0 ? const PlayerPage() : const WeatherPage(),
27+
bottomNavigationBar: BottomNavigationBar(
28+
items: const <BottomNavigationBarItem>[
29+
BottomNavigationBarItem(
30+
icon: Icon(Icons.ondemand_video),
31+
label: 'Player',
35432
),
355-
),
356-
actions: <Widget>[
357-
TextButton(
358-
child: const Text('OK'),
359-
onPressed: () {
360-
Navigator.of(context).pop();
361-
},
33+
BottomNavigationBarItem(
34+
icon: Icon(Icons.wb_sunny),
35+
label: 'Weather',
36236
),
36337
],
364-
);
365-
},
38+
currentIndex: _selectedIndex,
39+
onTap: (int index) {
40+
setState(() {
41+
_selectedIndex = index;
42+
});
43+
},
44+
),
45+
),
36646
);
36747
}
36848
}

0 commit comments

Comments
 (0)