Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): make setUrl async, make properties of WrappedPlayer private #1439

Merged
merged 2 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/audioplayers_web/lib/audioplayers_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class AudioplayersPlugin extends AudioplayersPlatform with StreamsInterface {
String url, {
bool? isLocal,
}) async {
getOrCreatePlayer(playerId).setUrl(url);
await getOrCreatePlayer(playerId).setUrl(url);
}

@override
Expand Down
114 changes: 57 additions & 57 deletions packages/audioplayers_web/lib/wrapped_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,126 +10,126 @@ class WrappedPlayer {
final String playerId;
final StreamsInterface streamsInterface;

double? pausedAt;
double currentVolume = 1.0;
double currentPlaybackRate = 1.0;
ReleaseMode currentReleaseMode = ReleaseMode.release;
String? currentUrl;
bool isPlaying = false;
double? _pausedAt;
double _currentVolume = 1.0;
double _currentPlaybackRate = 1.0;
ReleaseMode _currentReleaseMode = ReleaseMode.release;
String? _currentUrl;
bool _isPlaying = false;

AudioElement? player;
StereoPannerNode? stereoPanner;
StreamSubscription? playerTimeUpdateSubscription;
StreamSubscription? playerEndedSubscription;
StreamSubscription? playerLoadedDataSubscription;
StreamSubscription? playerPlaySubscription;
StreamSubscription? playerSeekedSubscription;
StereoPannerNode? _stereoPanner;
StreamSubscription? _playerTimeUpdateSubscription;
StreamSubscription? _playerEndedSubscription;
StreamSubscription? _playerLoadedDataSubscription;
StreamSubscription? _playerPlaySubscription;
StreamSubscription? _playerSeekedSubscription;

WrappedPlayer(this.playerId, this.streamsInterface);

void setUrl(String url) {
if (currentUrl == url) {
Future<void> setUrl(String url) async {
if (_currentUrl == url) {
return; // nothing to do
}
currentUrl = url;
_currentUrl = url;

stop();
recreateNode();
if (isPlaying) {
resume();
if (_isPlaying) {
await resume();
}
}

void setVolume(double volume) {
currentVolume = volume;
_currentVolume = volume;
player?.volume = volume;
}

void setBalance(double balance) {
stereoPanner?.pan.value = balance;
_stereoPanner?.pan.value = balance;
}

void setPlaybackRate(double rate) {
currentPlaybackRate = rate;
_currentPlaybackRate = rate;
player?.playbackRate = rate;
}

void recreateNode() {
if (currentUrl == null) {
if (_currentUrl == null) {
return;
}

final p = player = AudioElement(currentUrl);
final p = player = AudioElement(_currentUrl);
// As the AudioElement is created dynamically via script,
// features like 'stereo panning' need the CORS header to be enabled.
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
p.crossOrigin = 'anonymous';
p.loop = shouldLoop();
p.volume = currentVolume;
p.playbackRate = currentPlaybackRate;
p.volume = _currentVolume;
p.playbackRate = _currentPlaybackRate;

// setup stereo panning
final audioContext = JsAudioContext();
final source = audioContext.createMediaElementSource(player!);
stereoPanner = audioContext.createStereoPanner();
source.connect(stereoPanner!);
stereoPanner?.connect(audioContext.destination);
_stereoPanner = audioContext.createStereoPanner();
source.connect(_stereoPanner!);
_stereoPanner?.connect(audioContext.destination);

playerPlaySubscription = p.onPlay.listen((_) {
_playerPlaySubscription = p.onPlay.listen((_) {
streamsInterface.emitDuration(
playerId,
p.duration.fromSecondsToDuration(),
);
});
playerLoadedDataSubscription = p.onLoadedData.listen((_) {
_playerLoadedDataSubscription = p.onLoadedData.listen((_) {
streamsInterface.emitDuration(
playerId,
p.duration.fromSecondsToDuration(),
);
});
playerTimeUpdateSubscription = p.onTimeUpdate.listen((_) {
_playerTimeUpdateSubscription = p.onTimeUpdate.listen((_) {
streamsInterface.emitPosition(
playerId,
p.currentTime.fromSecondsToDuration(),
);
});
playerSeekedSubscription = p.onSeeked.listen((_) {
_playerSeekedSubscription = p.onSeeked.listen((_) {
streamsInterface.emitSeekComplete(playerId);
});
playerEndedSubscription = p.onEnded.listen((_) {
pausedAt = 0;
_playerEndedSubscription = p.onEnded.listen((_) {
_pausedAt = 0;
player?.currentTime = 0;
streamsInterface.emitComplete(playerId);
});
}

bool shouldLoop() => currentReleaseMode == ReleaseMode.loop;
bool shouldLoop() => _currentReleaseMode == ReleaseMode.loop;

void setReleaseMode(ReleaseMode releaseMode) {
currentReleaseMode = releaseMode;
_currentReleaseMode = releaseMode;
player?.loop = shouldLoop();
}

void release() {
_cancel();
player = null;
stereoPanner = null;

playerLoadedDataSubscription?.cancel();
playerLoadedDataSubscription = null;
playerTimeUpdateSubscription?.cancel();
playerTimeUpdateSubscription = null;
playerEndedSubscription?.cancel();
playerEndedSubscription = null;
playerSeekedSubscription?.cancel();
playerSeekedSubscription = null;
playerPlaySubscription?.cancel();
playerPlaySubscription = null;
_stereoPanner = null;

_playerLoadedDataSubscription?.cancel();
_playerLoadedDataSubscription = null;
_playerTimeUpdateSubscription?.cancel();
_playerTimeUpdateSubscription = null;
_playerEndedSubscription?.cancel();
_playerEndedSubscription = null;
_playerSeekedSubscription?.cancel();
_playerSeekedSubscription = null;
_playerPlaySubscription?.cancel();
_playerPlaySubscription = null;
}

Future<void> start(double position) async {
isPlaying = true;
if (currentUrl == null) {
_isPlaying = true;
if (_currentUrl == null) {
return; // nothing to play yet
}
if (player == null) {
Expand All @@ -140,34 +140,34 @@ class WrappedPlayer {
}

Future<void> resume() async {
await start(pausedAt ?? 0);
await start(_pausedAt ?? 0);
}

void pause() {
pausedAt = player?.currentTime as double?;
isPlaying = false;
_pausedAt = player?.currentTime as double?;
_isPlaying = false;
player?.pause();
}

void stop() {
_cancel();
pausedAt = 0;
_pausedAt = 0;
player?.currentTime = 0;
}

void seek(int position) {
final seekPosition = position / 1000.0;
player?.currentTime = seekPosition;

if (!isPlaying) {
pausedAt = seekPosition;
if (!_isPlaying) {
_pausedAt = seekPosition;
}
}

void _cancel() {
isPlaying = false;
_isPlaying = false;
player?.pause();
if (currentReleaseMode == ReleaseMode.release) {
if (_currentReleaseMode == ReleaseMode.release) {
player = null;
}
}
Expand Down