-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Support For Providing A StartPosition With Track #713
Support For Providing A StartPosition With Track #713
Conversation
Summary: This adds support for providing a startPosition with a track. If a startPosition is provided, the track will start playing from the specified position. The position is in seconds. I chose to name it startPosition because we may want to add support for providing an endPosition as well in order to only play a sub-clip of a track. It’s not part of this PR as it requires additional changes to SwiftAudio on the iOS side. ExoPlayer on the Android side already supports this. Test Plan: - verified on both iOS and Android with the example app - used a new sound file that counts in order to easily verify that startPosition works as expected
When I try this, on Android, it appears to affect the reported duration and position values such that the duration is the "clipped" duration instead of the entire duration. For instance, if I have a track that has a total duration of 0:30, and I want to start at 0:10, the track starts and plays as expected at 0:10, however, the duration is reported as 0:20, and the position is 0:00 at the start. This means that progress indicators and timeline seek controls are affected. Is this what you intended, and found? It is different than the iOS behavior. |
Maybe you had a different use case in mind? My intended use case for this feature would be to "resume" a track at a given time. Perhaps where a user left off in a previous listening sessions. |
Yeah, it seems that clipping does not fit here - but I've found an example of setting initial position in expoplayer demo - https://github.com/google/ExoPlayer/blob/r2.10.4/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java#L447 - example just uses seekTo before setting a media source, probably that's the way? |
I think that is probably the correct way as well. However, I don't feel I have a good enough grasp on the Android native code to suggest an exact implementation. :( |
I can see multiple places that would work for adding this on "play". But I'm not seeing an obvious place to do a seek when the queue goes from one track to the next. In order to match the iOS implementation, you should be able to queue up multiple tracks, each with a start time, and have each of them start at the specified time. Does prepare() get called when transitioning to the next track? |
It was based on this PR, which turned out to have issues. doublesymmetry#713 (review)
I had only tested it in the example app and it seemed to do the right thing. But yes, it does cause a problem with the duration. The duration that is passed into a track (which the example didn't do), doesn't match with the actual length due to how it does the clipping. Yes, for the first item setting |
So using It works best for However for To make this work perfect as that it actually sets the seek before playing, the exoplayer has to be modified. There is already the notion of a startPosition (different from the one of the ClippingMediaSource) but as far as I can tell, it has to be exposed in order to use it for the case of resuming a track at a specific seek. That's how far I got last night. |
@Guichaguri Do you have any guidance for us, as to how/where to implement a |
I'd love to hear about your use case. I'm still confused about this PR, I can see two distinct features being mixed together:
In case you want the latter, the proper way is to seek to the start position before playing. |
Here's another question:
Should the Track 1 start to play from 0:10 or 0:00? |
currently the queue is hard to use ,why don't we let the js manage the queue? for gapless playback, emit a about to finish event,then js append the next track to preloading |
I think the use case is number 2. At least I know mine is. I want to start playing at a given time in order to resume where a user left off previously. The reason we are trying to implement this feature is: SwiftAudio provides the option to set an Regarding skipping to previous track, no I would NOT want it to start at the specified time. I would expect it to start at zero. However, in my case this is irrelevant because I am managing my own queue and only have one track at a time in the native queue. Maybe the better solution is some sort of |
@gaodeng The reason why we manage the queue is to allow gapless playback. We already plan to add a player that doesn't have a managed queue in v2, but that's a subject for another issue. @curiousdustin I totally agree with you, I think |
@Guichaguri, leaving the alternate Is this approach guaranteed to seek to the designated time without any chance of a tiny bit of audio playing before the seek happens? Is |
@Guichaguri , I would possibly start a PR for the (I'm still on 1.1.x because I haven't updated react yet) |
@curiousdustin - No, I don't think using @Guichaguri The goal of this PR was to add functionality that would allow providing an initialTime / initialSeek to any track. The use of ClippingMediaSource was incorrect (but this wasn't obvious at first with the example app). The problem it addresses is that in a playlist, if more than one track was previously played, we need to set an initial seek not just for the first item in the playlist but also subsequent items.
To answer your question as to what should happen if the user skips from Track 1 back to Track 2 (in the above example), Track 2 would play again from the previous initial seek based on both using Since I'm not 100% happy with using |
@FrankGoortani - I appreciate the vote of confidence but I'm not certain that we should move forward with the proposed solution. I'm using it internally for the time being but the proper solution should be to address this on ExpPlayer's side first (by adding support for this). |
@thorbenprimke, did you end up finding or creating a solution that doesn't rely on |
For those interested, I ended up creating a custom media source wrapper that allows setting a start time. It probably doesn't apply to all use cases but it seems to work for mine. It does not rely on It also allows seeking backward from the set starting point. I followed the example given here by the ExoPlayer team. Had to modify quite a bit because things have changed, but the spirit remains the same. Here are the relevant changes on my fork: |
So what's a workaround for this? I've tried calling seekTo() prior to calling play() and it plays from the start. If I call seekTo() after I call play() then it automatically pauses. |
@dcvz @bradleyflood it looks like there's some movement here. Is there anything I can do to help out? |
@dcvz @bradleyflood , sorry I'm not trying to be annoying, I greatly appreciate all your work on this project. But I'm pleading with you here. I want to solve this problem for you. I just want some high-level consensus regarding the proper solution before I spend time working on it. 🥺 🥺 🙏 |
I think here there's a big discontinuity between the two options for such an API. 1) providing an initial position parameter as part of the track. However this has the problem that this would be taken into account anytime that track plays, for example if you skip forward and you skip backward. The track will just continue to start at the initial time set. 2) we have methods allowing you to play a track starting at a designated position. For playing the first track, this should already be possible by adding items to the queue and seeking before calling === I personally think I'd be in favour of an approach like no. 2 instead of option 1. What do you think @mpivchev? For the interested parties here, is option 2 one that would fit your use cases? |
@dcvz thank you for responding! I really do appreciate it. FWIW the following interface would satisfy my requirements (effectively "Option 2" as I understand it): interface TrackPlayer {
public async play();
public async skipToNext(initialPosition?: number);
public async skipToPrevious(initialPosition?: number);
public async skip(index: number, initialPosition?: number);
} Also FWIW, the scenario of calling |
Hi @dcvz ! Great work on this library :) We are also in need of this functionality. Our use case is playing a queue of one or more tracks that has been previously started and then saved each tracks position. This would fit option 1 more, I guess, as the queue should be able to run by itself and when a track ends, the next one should automatically start on the stored position for that track. A patch from @gilbertl that uses the initialTime property for iOS makes our use case with option 1 doable with the current interface. As @jspizziri mentions, the seekTo before play works fine on Android, but not on iOS. |
The way I see it "Option 1" could be layered on top of "Option 2". If that's the case and we all agree that Option 2 would be a useful set of functionality then perhaps we could implement it and implement the rest later? |
I'd like to add my use-case to the mix, which I think tends towards needing Option 1 (which I do understand is a bit problematic from a multi-track queue perspective). In my case, I only ever add one track to the queue. If the user switches tracks, I always call reset before adding the new track. From my testing, I see that as soon as you add a remote (hls/dash) track to the queue and it is the "active" track, track-player will start buffering the track from the server. Yes I can seek immediately after adding, but there's still a bit of a delay, so track-player always starts buffering from position zero, even if I immediately seek afterwards. When I opened my issue a while back (#1330) I mentioned this "waste of bandwidth" as the main problem. It's honestly not really that big of a deal, but I just wanted to point it out in case it wasn't being considered. My use-case is an audiobook app in which you only ever have one "active" book, and you tend to listen for a long period of time. Switching between books is when I reset the player and load in a different track, but I restore the previous position from the server. But I can see another argument for Option 1 being something like a podcast app, where you can add multiple "episodes" to your queue, but you still always want to restore the playback position, not start playing from the beginning. Just my two cents! And thanks for this amazing library! ❤️ |
@dcvz any thoughts on the comments of the folks who have chimed in? |
Yeah, I've thought some more about it. I still think we should go with the option 2 approach. I think it still lends itself to being able to be used for the other use cases as well, albeit with a bit more work. If you're up for that exploration @jspizziri lets do it! I think not being able to seek on iOS is a bug that should be fixed. |
@dcvz I will put this in my schedule for next week, stay tuned! |
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
Support for the discussed interface is largely functional on this PR. I've recommended that we close this PR in favor of the other. With that said with the fix to iOS seek on load @dcvz is hesitant to merge it as this might be a non-issue at this point with a reasonable solution out of the box. There's an ongoing conversation around theoretical vs. actual performance that could use the input from the people on this thread. If you all could chime in and give your feedback or give the PR a test it would be helpful to determine what the future of the PR will be. |
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
…itial time when skipping add an optional parameter to the skip* methods to allow passing an initial playback time doublesymmetry#713 (comment)
#1413 has been merged, and I believe this feature will land in @dcvz I think this PR can be closed. |
Summary:
This adds support for providing a startPosition with a track. If a startPosition
is provided, the track will start playing from the specified position.
The position is in seconds.
I chose to name it startPosition because we may want to add support for providing
an endPosition as well in order to only play a sub-clip of a track. It’s not part of this
PR as it requires additional changes to SwiftAudio on the iOS side. ExoPlayer on the
Android side already supports this.
Test Plan: