Skip to content

Commit e5a1e4a

Browse files
committed
Merge branch 'feature/wasm' into minor
2 parents 2994f08 + 1e8ad86 commit e5a1e4a

File tree

7 files changed

+86
-140
lines changed

7 files changed

+86
-140
lines changed

audio_service/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Demonstrates how to use the audio_service plugin.
33
publish_to: 'none'
44

55
environment:
6-
sdk: ">=2.14.0 <4.0.0"
6+
sdk: ">=3.3.0 <4.0.0"
77
flutter: ">=3.0.0"
88

99
dependencies:

audio_service/example/web/index.html

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<!DOCTYPE html>
22
<html>
33
<head>
4+
<base href="$FLUTTER_BASE_HREF">
5+
46
<meta charset="UTF-8">
57
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
68
<meta name="description" content="A new Flutter project.">
@@ -18,16 +20,6 @@
1820
<link rel="manifest" href="manifest.json">
1921
</head>
2022
<body>
21-
<!-- This script installs service_worker.js to provide PWA functionality to
22-
application. For more information, see:
23-
https://developers.google.com/web/fundamentals/primers/service-workers -->
24-
<script>
25-
if ('serviceWorker' in navigator) {
26-
window.addEventListener('load', function () {
27-
navigator.serviceWorker.register('flutter_service_worker.js');
28-
});
29-
}
30-
</script>
31-
<script src="main.dart.js" type="application/javascript"></script>
23+
<script src="flutter_bootstrap.js" async></script>
3224
</body>
3325
</html>

audio_service/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ topics:
88
- background
99

1010
environment:
11-
sdk: ">=2.14.0 <4.0.0"
11+
sdk: ">=3.3.0 <4.0.0"
1212
flutter: ">=3.0.0"
1313

1414
dependencies:
@@ -31,8 +31,8 @@ dependencies:
3131
# path: audio_service_web
3232

3333
# Use these deps when publishing.
34-
audio_service_platform_interface: ^0.1.2
35-
audio_service_web: ^0.1.3
34+
audio_service_platform_interface: ^0.1.3
35+
audio_service_web: ^0.1.4
3636

3737
audio_session: ^0.1.20
3838
rxdart: '>=0.26.0 <0.29.0'

audio_service_web/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.1.4
2+
3+
* Migrated to package:web (@ali2236)
4+
15
## 0.1.3
26

37
* Support rxdart 0.28.x.

audio_service_web/lib/audio_service_web.dart

Lines changed: 66 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
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';
54

65
import 'package:audio_service_platform_interface/audio_service_platform_interface.dart';
76
import 'package:flutter/cupertino.dart';
87
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
8+
import 'package:web/web.dart' as web;
9+
910
import 'js/media_session_web.dart';
1011

1112
class AudioServiceWeb extends AudioServicePlatform {
1213
static void registerWith(Registrar registrar) {
1314
AudioServicePlatform.instance = AudioServiceWeb();
1415
}
1516

17+
web.MediaSession get _mediaSession => web.window.navigator.mediaSession;
18+
1619
final _mediaSessionSupported = _SupportChecker(
17-
() => js.context.hasProperty('MediaSession'),
20+
() => js.globalContext.hasProperty('MediaSession'.toJS).toDart,
1821
"MediaSession is not supported in this browser, so plugin is no-op",
1922
);
2023
final _setPositionStateSupported = _SupportChecker(
21-
() => hasProperty(html.window.navigator.mediaSession!, 'setPositionState'),
24+
() => web.window.navigator.mediaSession
25+
.hasProperty('setPositionState'.toJS)
26+
.toDart,
2227
"MediaSession.setPositionState is not supported in this browser",
2328
);
2429

@@ -39,60 +44,71 @@ class AudioServiceWeb extends AudioServicePlatform {
3944
final state = request.state;
4045

4146
if (state.processingState == AudioProcessingStateMessage.idle) {
42-
MediaSession.playbackState = MediaSessionPlaybackState.none;
47+
_mediaSession.playbackState = MediaSessionPlaybackState.none;
4348
} else {
4449
if (state.playing) {
45-
MediaSession.playbackState = MediaSessionPlaybackState.playing;
50+
_mediaSession.playbackState = MediaSessionPlaybackState.playing;
4651
} else {
47-
MediaSession.playbackState = MediaSessionPlaybackState.paused;
52+
_mediaSession.playbackState = MediaSessionPlaybackState.paused;
4853
}
4954
}
5055

5156
for (final control in state.controls) {
5257
switch (control.action) {
5358
case MediaActionMessage.play:
54-
MediaSession.setActionHandler(
59+
_mediaSession.setActionHandler(
5560
MediaSessionActions.play,
56-
(details) => handlerCallbacks?.play(const PlayRequest()),
61+
((MediaSessionActionDetails details) {
62+
handlerCallbacks?.play(const PlayRequest());
63+
}).toJS,
5764
);
5865
break;
5966
case MediaActionMessage.pause:
60-
MediaSession.setActionHandler(
67+
_mediaSession.setActionHandler(
6168
MediaSessionActions.pause,
62-
(details) => handlerCallbacks?.pause(const PauseRequest()),
69+
((MediaSessionActionDetails details) {
70+
handlerCallbacks?.pause(const PauseRequest());
71+
}).toJS,
6372
);
6473
break;
6574
case MediaActionMessage.skipToPrevious:
66-
MediaSession.setActionHandler(
75+
_mediaSession.setActionHandler(
6776
MediaSessionActions.previoustrack,
68-
(details) =>
69-
handlerCallbacks?.skipToPrevious(const SkipToPreviousRequest()),
77+
((MediaSessionActionDetails details) {
78+
handlerCallbacks?.skipToPrevious(const SkipToPreviousRequest());
79+
}).toJS,
7080
);
7181
break;
7282
case MediaActionMessage.skipToNext:
73-
MediaSession.setActionHandler(
83+
_mediaSession.setActionHandler(
7484
MediaSessionActions.nexttrack,
75-
(details) =>
76-
handlerCallbacks?.skipToNext(const SkipToNextRequest()),
85+
((MediaSessionActionDetails details) {
86+
handlerCallbacks?.skipToNext(const SkipToNextRequest());
87+
}).toJS,
7788
);
7889
break;
7990
case MediaActionMessage.rewind:
80-
MediaSession.setActionHandler(
91+
_mediaSession.setActionHandler(
8192
MediaSessionActions.seekbackward,
82-
(details) => handlerCallbacks?.rewind(const RewindRequest()),
93+
((MediaSessionActionDetails details) {
94+
handlerCallbacks?.rewind(const RewindRequest());
95+
}).toJS,
8396
);
8497
break;
8598
case MediaActionMessage.fastForward:
86-
MediaSession.setActionHandler(
99+
_mediaSession.setActionHandler(
87100
MediaSessionActions.seekforward,
88-
(details) =>
89-
handlerCallbacks?.fastForward(const FastForwardRequest()),
101+
((MediaSessionActionDetails details) {
102+
handlerCallbacks?.fastForward(const FastForwardRequest());
103+
}).toJS,
90104
);
91105
break;
92106
case MediaActionMessage.stop:
93-
MediaSession.setActionHandler(
107+
_mediaSession.setActionHandler(
94108
MediaSessionActions.stop,
95-
(details) => handlerCallbacks?.stop(const StopRequest()),
109+
((MediaSessionActionDetails details) {
110+
handlerCallbacks?.stop(const StopRequest());
111+
}).toJS,
96112
);
97113
break;
98114
default:
@@ -104,14 +120,15 @@ class AudioServiceWeb extends AudioServicePlatform {
104120
for (final message in state.systemActions) {
105121
switch (message) {
106122
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);
115132
break;
116133
default:
117134
// no-op
@@ -128,7 +145,7 @@ class AudioServiceWeb extends AudioServicePlatform {
128145
final position = _minDuration(state.updatePosition, duration);
129146

130147
// Browsers expect for seconds
131-
MediaSession.setPositionState(MediaSessionPositionState(
148+
_mediaSession.setPositionState(web.MediaPositionState(
132149
duration: duration.inMilliseconds / 1000,
133150
playbackRate: state.speed,
134151
position: position.inMilliseconds / 1000,
@@ -147,30 +164,29 @@ class AudioServiceWeb extends AudioServicePlatform {
147164
return;
148165
}
149166
mediaItem = request.mediaItem;
150-
final artist = mediaItem!.artist;
151-
final album = mediaItem!.album;
167+
final artist = mediaItem!.artist ?? '';
168+
final album = mediaItem!.album ?? '';
152169
final artUri = mediaItem!.artUri;
153170

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+
);
165182
}
166183

167184
@override
168185
Future<void> stopService(StopServiceRequest request) async {
169186
if (!_mediaSessionSupported.check()) {
170187
return;
171188
}
172-
final session = html.window.navigator.mediaSession!;
173-
session.metadata = null;
189+
_mediaSession.metadata = null;
174190
mediaItem = null;
175191
}
176192

@@ -193,6 +209,7 @@ class _SupportChecker {
193209
_SupportChecker(this._checkCallback, this._warningMessage);
194210

195211
bool _logged = false;
212+
196213
bool check() {
197214
final result = _checkCallback();
198215
if (!_logged && !result) {

audio_service_web/lib/js/media_session_web.dart

Lines changed: 5 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,7 @@
66
@JS()
77
library media_session_web;
88

9-
import 'dart:js' as js;
10-
import 'dart:html' as html;
11-
import 'package:js/js.dart';
12-
13-
/// The interface to the Media Session API which allows a web page
14-
/// to provide custom behaviors for standard media playback interactions,
15-
/// and to report metadata that can be sent by the user agent
16-
/// to the device or operating system for presentation in standardized
17-
/// user interface elements.
18-
@JS('navigator.mediaSession')
19-
class MediaSession {
20-
/// Returns an instance of [html.MediaMetadata], which contains rich media
21-
/// metadata for display in a platform UI.
22-
@JS('metadata')
23-
external static html.MediaMetadata metadata;
24-
25-
/// Indicates whether the current media session is playing.
26-
///
27-
/// See [MediaSessionPlaybackState] for possible values.
28-
@JS('playbackState')
29-
external static String playbackState;
30-
31-
/// Sets an action handler for a media session action, such as play or pause.
32-
static void setActionHandler(
33-
String action,
34-
MediaSessionActionHandler callback,
35-
) =>
36-
_setActionHandler(action, js.allowInterop(callback));
37-
38-
@JS('setActionHandler')
39-
external static void _setActionHandler(
40-
String action,
41-
MediaSessionActionHandler callback,
42-
);
43-
44-
/// Sets the current playback position and speed of the media currently being presented.
45-
@JS('setPositionState')
46-
external static void setPositionState(MediaSessionPositionState? state);
47-
}
9+
import 'dart:js_interop';
4810

4911
/// Media session playback state types.
5012
///
@@ -90,7 +52,7 @@ typedef MediaSessionActionHandler = dynamic Function(MediaSessionActionDetails);
9052
/// The dictionary parameter for [MediaSessionActionHandler] callback.
9153
@JS()
9254
@anonymous
93-
class MediaSessionActionDetails {
55+
extension type MediaSessionActionDetails._(JSObject _) implements JSObject {
9456
/// An action type string taken from the [MediaActions], indicating which
9557
/// type of action needs to be performed.
9658
external String get action;
@@ -105,21 +67,21 @@ class MediaSessionActionDetails {
10567
/// This property can be used to indicate that you should use the shortest possible
10668
/// method to seek the media. This property is not included on the final action in
10769
/// the seek sequence in this situation.
108-
external bool get fastSeek;
70+
external bool? get fastSeek;
10971

11072
/// If the action is either `seekforward` or `seekbackward`
11173
/// and this property is present, it is a floating point value which indicates
11274
/// the seek interval.
11375
///
11476
/// If this property isn't present, those actions should choose a reasonable
11577
/// default interval.
116-
external double get seekOffset;
78+
external double? get seekOffset;
11779

11880
/// If the action is `seekto`, this property is present and
11981
/// indicates the absolute time within the media to move the playback position to.
12082
///
12183
/// This property is not present for other action types.
122-
external double get seekTime;
84+
external double? get seekTime;
12385

12486
/// Creates the details.
12587
external factory MediaSessionActionDetails({
@@ -129,31 +91,3 @@ class MediaSessionActionDetails {
12991
double? seekTime,
13092
});
13193
}
132-
133-
/// A representation of the current playback.
134-
///
135-
/// The dictionary parameter for [MediaSession.setPositionState].
136-
@JS()
137-
@anonymous
138-
class MediaSessionPositionState {
139-
/// Duration in seconds.
140-
external double get duration;
141-
142-
/// Playback rate.
143-
///
144-
/// Can be positive to represent forward playback or negative to
145-
/// represent backwards playback.
146-
///
147-
/// Cannot be zero.
148-
external double get playbackRate;
149-
150-
/// Position in seconds.
151-
external double get position;
152-
153-
/// Creates the position state.
154-
external factory MediaSessionPositionState({
155-
double? duration,
156-
double? playbackRate,
157-
double? position,
158-
});
159-
}

0 commit comments

Comments
 (0)