1
1
import 'dart:async' ;
2
- import 'dart:html' as html;
3
- import 'dart:js' as js;
4
- import 'dart:js_util' ;
2
+ import 'dart:js_interop' as js;
3
+ import 'dart:js_interop_unsafe' ;
5
4
6
5
import 'package:audio_service_platform_interface/audio_service_platform_interface.dart' ;
7
6
import 'package:flutter/cupertino.dart' ;
8
7
import 'package:flutter_web_plugins/flutter_web_plugins.dart' ;
8
+ import 'package:web/web.dart' as web;
9
+
9
10
import 'js/media_session_web.dart' ;
10
11
11
12
class AudioServiceWeb extends AudioServicePlatform {
12
13
static void registerWith (Registrar registrar) {
13
14
AudioServicePlatform .instance = AudioServiceWeb ();
14
15
}
15
16
17
+ web.MediaSession get _mediaSession => web.window.navigator.mediaSession;
18
+
16
19
final _mediaSessionSupported = _SupportChecker (
17
- () => js.context .hasProperty ('MediaSession' ) ,
20
+ () => js.globalContext .hasProperty ('MediaSession' .toJS).toDart ,
18
21
"MediaSession is not supported in this browser, so plugin is no-op" ,
19
22
);
20
23
final _setPositionStateSupported = _SupportChecker (
21
- () => hasProperty (html.window.navigator.mediaSession! , 'setPositionState' ),
24
+ () => web.window.navigator.mediaSession
25
+ .hasProperty ('setPositionState' .toJS)
26
+ .toDart,
22
27
"MediaSession.setPositionState is not supported in this browser" ,
23
28
);
24
29
@@ -39,60 +44,71 @@ class AudioServiceWeb extends AudioServicePlatform {
39
44
final state = request.state;
40
45
41
46
if (state.processingState == AudioProcessingStateMessage .idle) {
42
- MediaSession .playbackState = MediaSessionPlaybackState .none;
47
+ _mediaSession .playbackState = MediaSessionPlaybackState .none;
43
48
} else {
44
49
if (state.playing) {
45
- MediaSession .playbackState = MediaSessionPlaybackState .playing;
50
+ _mediaSession .playbackState = MediaSessionPlaybackState .playing;
46
51
} else {
47
- MediaSession .playbackState = MediaSessionPlaybackState .paused;
52
+ _mediaSession .playbackState = MediaSessionPlaybackState .paused;
48
53
}
49
54
}
50
55
51
56
for (final control in state.controls) {
52
57
switch (control.action) {
53
58
case MediaActionMessage .play:
54
- MediaSession .setActionHandler (
59
+ _mediaSession .setActionHandler (
55
60
MediaSessionActions .play,
56
- (details) => handlerCallbacks? .play (const PlayRequest ()),
61
+ ((MediaSessionActionDetails details) {
62
+ handlerCallbacks? .play (const PlayRequest ());
63
+ }).toJS,
57
64
);
58
65
break ;
59
66
case MediaActionMessage .pause:
60
- MediaSession .setActionHandler (
67
+ _mediaSession .setActionHandler (
61
68
MediaSessionActions .pause,
62
- (details) => handlerCallbacks? .pause (const PauseRequest ()),
69
+ ((MediaSessionActionDetails details) {
70
+ handlerCallbacks? .pause (const PauseRequest ());
71
+ }).toJS,
63
72
);
64
73
break ;
65
74
case MediaActionMessage .skipToPrevious:
66
- MediaSession .setActionHandler (
75
+ _mediaSession .setActionHandler (
67
76
MediaSessionActions .previoustrack,
68
- (details) =>
69
- handlerCallbacks? .skipToPrevious (const SkipToPreviousRequest ()),
77
+ ((MediaSessionActionDetails details) {
78
+ handlerCallbacks? .skipToPrevious (const SkipToPreviousRequest ());
79
+ }).toJS,
70
80
);
71
81
break ;
72
82
case MediaActionMessage .skipToNext:
73
- MediaSession .setActionHandler (
83
+ _mediaSession .setActionHandler (
74
84
MediaSessionActions .nexttrack,
75
- (details) =>
76
- handlerCallbacks? .skipToNext (const SkipToNextRequest ()),
85
+ ((MediaSessionActionDetails details) {
86
+ handlerCallbacks? .skipToNext (const SkipToNextRequest ());
87
+ }).toJS,
77
88
);
78
89
break ;
79
90
case MediaActionMessage .rewind:
80
- MediaSession .setActionHandler (
91
+ _mediaSession .setActionHandler (
81
92
MediaSessionActions .seekbackward,
82
- (details) => handlerCallbacks? .rewind (const RewindRequest ()),
93
+ ((MediaSessionActionDetails details) {
94
+ handlerCallbacks? .rewind (const RewindRequest ());
95
+ }).toJS,
83
96
);
84
97
break ;
85
98
case MediaActionMessage .fastForward:
86
- MediaSession .setActionHandler (
99
+ _mediaSession .setActionHandler (
87
100
MediaSessionActions .seekforward,
88
- (details) =>
89
- handlerCallbacks? .fastForward (const FastForwardRequest ()),
101
+ ((MediaSessionActionDetails details) {
102
+ handlerCallbacks? .fastForward (const FastForwardRequest ());
103
+ }).toJS,
90
104
);
91
105
break ;
92
106
case MediaActionMessage .stop:
93
- MediaSession .setActionHandler (
107
+ _mediaSession .setActionHandler (
94
108
MediaSessionActions .stop,
95
- (details) => handlerCallbacks? .stop (const StopRequest ()),
109
+ ((MediaSessionActionDetails details) {
110
+ handlerCallbacks? .stop (const StopRequest ());
111
+ }).toJS,
96
112
);
97
113
break ;
98
114
default :
@@ -104,14 +120,15 @@ class AudioServiceWeb extends AudioServicePlatform {
104
120
for (final message in state.systemActions) {
105
121
switch (message) {
106
122
case MediaActionMessage .seek:
107
- MediaSession .setActionHandler ('seekto' ,
108
- (MediaSessionActionDetails details) {
109
- // Browsers use seconds
110
- handlerCallbacks? .seek (SeekRequest (
111
- position:
112
- Duration (milliseconds: (details.seekTime * 1000 ).round ()),
113
- ));
114
- });
123
+ _mediaSession.setActionHandler (
124
+ 'seekto' ,
125
+ ((MediaSessionActionDetails details) {
126
+ // Browsers use seconds
127
+ handlerCallbacks? .seek (SeekRequest (
128
+ position: Duration (
129
+ milliseconds: (details.seekTime! * 1000 ).round ()),
130
+ ));
131
+ }).toJS);
115
132
break ;
116
133
default :
117
134
// no-op
@@ -128,7 +145,7 @@ class AudioServiceWeb extends AudioServicePlatform {
128
145
final position = _minDuration (state.updatePosition, duration);
129
146
130
147
// Browsers expect for seconds
131
- MediaSession .setPositionState (MediaSessionPositionState (
148
+ _mediaSession .setPositionState (web. MediaPositionState (
132
149
duration: duration.inMilliseconds / 1000 ,
133
150
playbackRate: state.speed,
134
151
position: position.inMilliseconds / 1000 ,
@@ -147,30 +164,29 @@ class AudioServiceWeb extends AudioServicePlatform {
147
164
return ;
148
165
}
149
166
mediaItem = request.mediaItem;
150
- final artist = mediaItem! .artist;
151
- final album = mediaItem! .album;
167
+ final artist = mediaItem! .artist ?? '' ;
168
+ final album = mediaItem! .album ?? '' ;
152
169
final artUri = mediaItem! .artUri;
153
170
154
- MediaSession .metadata = html .MediaMetadata (< String , dynamic > {
155
- 'title' : mediaItem ! .title,
156
- if (artist != null ) 'artist' : artist ,
157
- if (album != null ) 'album' : album ,
158
- 'artwork' : [
159
- {
160
- 'src' : artUri,
161
- ' sizes' : '512x512' ,
162
- }
163
- ] ,
164
- } );
171
+ _mediaSession .metadata = web .MediaMetadata (
172
+ web. MediaMetadataInit (
173
+ title : mediaItem ! .title ,
174
+ artist : artist ,
175
+ album : album,
176
+ artwork : [
177
+ if ( artUri != null )
178
+ web. MediaImage (src : artUri. toString (), sizes: '512x512' ) ,
179
+ ].toJS,
180
+ ) ,
181
+ );
165
182
}
166
183
167
184
@override
168
185
Future <void > stopService (StopServiceRequest request) async {
169
186
if (! _mediaSessionSupported.check ()) {
170
187
return ;
171
188
}
172
- final session = html.window.navigator.mediaSession! ;
173
- session.metadata = null ;
189
+ _mediaSession.metadata = null ;
174
190
mediaItem = null ;
175
191
}
176
192
@@ -193,6 +209,7 @@ class _SupportChecker {
193
209
_SupportChecker (this ._checkCallback, this ._warningMessage);
194
210
195
211
bool _logged = false ;
212
+
196
213
bool check () {
197
214
final result = _checkCallback ();
198
215
if (! _logged && ! result) {
0 commit comments