-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Implement Un-eject #4668
Implement Un-eject #4668
Conversation
src/mixer/playermanager.cpp
Outdated
connect(pSampler, | ||
&BaseTrackPlayer::trackUnloaded, | ||
this, | ||
&PlayerManager::slotStoreParkedTrack); | ||
} | ||
|
||
// Connect the player to the analyzer queue so that loaded tracks are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided not to connect the signal to the preview deck, because that deck will have a lot more churn, but that could be changed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds reasonable
will add a test if people like the idea |
Makes sense to me! |
there are some remaining questions around exact implementation but I think there's consensus at least for the concept. We can start with this and iterate as needed |
src/mixer/playermanager.cpp
Outdated
VERIFY_OR_DEBUG_ASSERT(track) { | ||
return; | ||
} | ||
m_pLastEjectedTrack = track; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping more tracks loaded in-memory for an unforeseeable and unlimited amount of time will only fuel the various issues we already experience with delayed database updates and metadata synchronization. Uncontrolled accumulation of state gets you into trouble.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The trackId can be stored without issues, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Performance wise it is a good idea to use the pointer.
How is the situation with our cache? Is guaranteed that the last ejected track is kept in cache?
Holding the pointer here enforces that, which is a good idea from that perspective.
The the issue with this is that it is hidden behind the scenes and it is hard to predict when the metadata is written to the file. We are already in that state, right? Is this relevant here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see stale search results all the time, caused by these kind of issues. It's not only about metadata.
And it is bad practice to keep data alive for an unlimited of time. If you don't use the deck anymore the pointer is kept alive until Mixxx is finally closed.
Either store an ID are use a timer to reset the pointer periodically. I guess we have a similar caching issue in BaseTrackCache.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And remember. These are fat QObjects with all the wiring that may cause all kinds of weird side-effects. This design is already unmaintainable. Don't make the situation worse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah we can switch this to an ID.
As to Daniel's question above, if the ID is invalid (because of something strange like the user deleted the file) the track load will simply fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any hint for how to load a track by trackid? I am a little lost in the library code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TrackCollectonManager::getTrackById()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is fixed
Schould this work for any unload action, like replacing a track? Or only for explicit "ejects"? A corner case would be to load an not existing track. Does it eject the old? Is this considered as an eject action? |
src/mixer/basetrackplayer.cpp
Outdated
return; | ||
} | ||
if (!m_pLoadedTrack) { | ||
auto lastEjected = m_pPlayerManager->getLastEjectedTrack(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not know what lastEjected is here. So I would prefer to either rename it or replace auto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/mixer/playermanager.cpp
Outdated
connect(pSampler, | ||
&BaseTrackPlayer::trackUnloaded, | ||
this, | ||
&PlayerManager::slotStoreParkedTrack); | ||
} | ||
|
||
// Connect the player to the analyzer queue so that loaded tracks are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds reasonable
src/mixer/playermanager.cpp
Outdated
VERIFY_OR_DEBUG_ASSERT(track) { | ||
return; | ||
} | ||
m_pLastEjectedTrack = track; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Performance wise it is a good idea to use the pointer.
How is the situation with our cache? Is guaranteed that the last ejected track is kept in cache?
Holding the pointer here enforces that, which is a good idea from that perspective.
The the issue with this is that it is hidden behind the scenes and it is hard to predict when the metadata is written to the file. We are already in that state, right? Is this relevant here?
any unload would trigger this, including replacing a track in a deck |
In Zulip I also threw in "un-replace", i.e. reload the track which was (accidentally) replaced. |
I would really prefer not to implement a double-click function in this first change. Can that wait for a followup? |
Sure, no hurry. I was just wondering if you think this is a valid use case / extension. If so, it'll probably be better to consider it now already, instead of having to bend over afterwards. |
Cool. Yeah I think an un-replace would be useful, and wouldn't be hard to implement with this as a foundation -- it could be a new CO, or a doubleclick / long press CO, and hook into the same basic structure. The refactor of the eject mechanism into playermanager is what makes it possible. |
I believe notes are addressed. I now store the trackid instead of trackpointer to free the resources. The test is pretty heavy now because we need a database to do the library lookup, but it's not so bad. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thank you!
Oh there is an Qt 6 issue:
|
I have been unable to install / test QT6. Can someone else figure out what it's complaining about? (a stack trace would help) |
or can we just disable the test on qt6 for now |
I don't get the bad_alloc error but these 3 tests fail:
|
looks like I'm double-creating a Library. |
That was unpleasant -- it would be nice if we could create a test-friendly coreservices mode, that would simplify a lot of this test. |
@daschuer can you retest with qt6 and if it still crashes can you build with |
I'm not @daschuer but here's your stack trace:
|
Try again -- and if it fails again can you print out the values of m_data.size() and iSize at the crash point? those values should be available. And also too, if you know the exact version of qt6 you have I can be more sure about which assertion is triggering the error. But I think that change might fix it. |
|
it looks like some invalid effect request is getting created with a bad channelhandle. |
asan:
|
ok so we are passing around pointers to channel handles, and I believe those pointers become invalid -- perhaps due to them being pointers inside a QVarLengthArray |
The Bad Line: https://github.com/mixxxdj/mixxx/blob/main/src/effects/effectchain.cpp#L397 this address becomes invalid |
I agree that this code is bad. But it does not take the address of a temporary, that's not true. It takes the address of a reference. If this is safe or not depends on the outer context. |
My suspicion is that something is awry with the way EngineChannels are constructed in the test environment. |
@be I checked the effects and |
that could well be the case but I've been checking against coreservices and can't find anything different yet |
Running the test repeatedly with #4675 applied always succeeded when built with Qt 6. |
with #4672 the test crash should be fixed |
ah sorry a bunch of debug crap snuck in |
When ejecting a track, save a pointer to the ejected track. If the user presses eject on an empty track in any deck or sampler, the saved track is loaded. The track is loaded fresh, not as a "Deck clone" operation. This enables a sort of "eject undo" as well as "track stashing". It requires no changes to controller configs. This required a refactor of the eject code to remove it from the EngineBuffer. Tests still pass. Hand-testing works.
Updated test to exercise the library lookup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks reasonable so far.
@daschuer I didn't test it and also didn't follow the discussions about this feature closely. That's why I won't press Merge myself.
I did a brief test and it is still working. Thank you very much. |
When ejecting a track, save a pointer to the ejected track. If the user presses eject on an empty track in any deck or sampler, the saved track is loaded.
The track is loaded fresh, not as a "Deck clone" operation.
This enables a sort of "eject undo" as well as "track stashing". It requires no changes to controller configs.
This required a refactor of the eject code to remove it from the EngineBuffer. Tests still pass. Hand-testing works.