-
-
Notifications
You must be signed in to change notification settings - Fork 603
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
ConcatenatingAudioSource: currentIndexStream - a way to check if the index change is due to either a track ending or a manual seek #174
Comments
Can you explain a little more about how this API works? If you have to call an API other than just_audio to skip to a track, then I assume you are not using just_audio's Then just to clarify, why wouldn't this work? if (newIndex = index + 1) api.next();
else if (newIndex = index - 1) api.previous();
else api.jumpTo(newIndex); |
I'm actually using both - the API allows me to see up to one song in advance, so I add the upcoming song to the ConcatenatingMediaSource for gapless playback. I need to listen to position changes so I know when to tell the API the track ended, and request the next upcoming song. Your above example works, but the API has different calls for skipping to the next track, and being notified that the track ended naturally. These can affect song recommendations, so it's important I use the right one. At the moment, there's no way to known which one to use (other than perhaps flipping a boolean in audio_service's onSkipToNext, but that's pretty messy). ExoPlayer at least sends a different event enum for both cases, but the plugin does the exact same thing for both - so the information is lost. |
I understand you now. I'll have to think on how to fit this into the current API, but in the meantime, you can possibly try a better workaround: bool skipped = false;
void skipTo(int index) {
skipped = true;
player.seek(Duration.zero, index: index);
}
player.currentIndexStream.listen((index) {
if (index == null) return; // haven't tested this
if (skipped) {
// call API one way
} else {
// call API the other way
}
skipped = false;
}); |
Thanks. That's what I'll do for now. |
As mentioned in #316, I have a similar requirement that could be resolved with something similar to ExoPlayer's onPositionDiscontinuity listener. I have a music player that uses Simply tracking changes to I tried listening to the I suppose I could do something like: bool isComplete = false
if (position > duration - Duration(milliseconds: 100)) {
isComplete = true;
/// log the listen
} else if (position == Duration.zero) {
isComplete = false;
} But this has some code smell. |
That's probably the easiest way to go about it. Another way is to observe /// The current position of the player.
Duration get position {
if (playing && processingState == ProcessingState.ready) {
final result = _playbackEvent.updatePosition +
(DateTime.now().difference(_playbackEvent.updateTime)) * speed;
return _playbackEvent.duration == null ||
result <= _playbackEvent.duration!
? result
: _playbackEvent.duration!;
} else {
return _playbackEvent.updatePosition;
}
} So what you could do is compare the current playback event with the last playback event and use the same calculation above to project both playback events to their projected current positions and compare if they're approximately equal. If they're not, then you have detected an actual time discontinuity. My previous workaround listed above will help you then distinguish that from a time discontinuity caused by a manual seek. (playbackEventStream as ValueStream<Duration>).pairwise().listen((pair) {
final lastEvent = pair.first;
final thisEvent = pair.last;
// positionOf would be your copy of the above projection calculation
final lastProjectedPosition = positionOf(lastEvent);
final thisProjectedPosition = positionOf(thisEvent);
// make your own roughlyEqual function with some desired epsilon
if (!roughlyEqual(lastProjectedPosition, thisProjectedPosition)) {
// time discontinuity
if (manualSeek) {
// handle manual seek
manualSeek = false;
} else {
// track completed
}
}
}); You'd also need to set bool manualSeek = false;
Future<void> seek(final Duration position, {int index}) async {
manualSeek = true;
await _player.seek(position, index: index);
} |
This is now implemented in the Usage: player.positionDiscontinuityReasonStream.listen((reason) {
switch (reason) {
case PositionDiscontinuityReason.seek:
break;
case PositionDiscontinuityReason.autoAdvance:
break;
}
}); The implementation was purely in Dart by observing the cues mentioned in the comments above, so it should work across platforms. Not sure about the API naming, or whether I need other enum values, so feedback is welcome before I release this. |
I've changed the API to this: player.positionDiscontinuityStream.listen((discontinuity) {
switch (discontinuity.reason) {
case PositionDiscontinuityReason.seek:
break;
case PositionDiscontinuityReason.autoAdvance:
break;
}
}); The stream name is now shorter and refers to a data structure containing 1) the reason, 2) the previous playback event, and 3) the present playback event. I've also updated |
This is now merged. |
Published! 0.9.28. |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs, or use StackOverflow if you need help with just_audio. |
Is your feature request related to a problem? Please describe.
The audio server I'm using requires different API calls to skip to the next track and skip to an arbitrary track. The latter is slower than the former, and song recommendations are effected, so I'd like to use the appropriate call when possible.
Describe the solution you'd like
It'd be great if there was perhaps a dedicated stream for index changes that not only includes the index, but also a reason for the change - something like ExoPlayer's
onPositionDiscontinuity
callback.Describe alternatives you've considered
A semi-workaround at the moment is to store the last index in a variable and compare that with the new one to see if there's a gap of more than 1 - but this still leaves it impossible to tell the difference between a user skipping to the next song and the song ending.
Additional context
That's it.
The text was updated successfully, but these errors were encountered: