-
-
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
SoundSource Plugin API: Version 8 #578
SoundSource Plugin API: Version 8 #578
Conversation
A simple C++ API that reduces the chance of memory leaks that were imminent in the previous C/C++ version. Error handling and logging in SoundSourceProxy while loading plugins has been improved.
I've bumped the SoundSource plugin API version from 7 to 8, re-defined the public library functions, and did some cleanup. |
SoundSourceProvider is a generic interface that will implemented both by plugin libraries as well as built-in sound sources. This will simplify the selection of an appropriate SoundSource in SoundSourceProxy and is useful for future extensions like selecting one out of multiple providers for each file type.
What has begun as a simple bug fix is now a refactoring of the SoundSource plugin framework ;) |
At least this is how it works in 1.12.
inline QString getLocalFileName() const { | ||
DEBUG_ASSERT(isLocalFile()); |
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.
What happens on windows with network shares?
There is a pending bug for SMB locations
https://bugs.launchpad.net/mixxx/+bug/918222
Will this fail here?
@daschuer: I've reset the branch to the previous state without the priority extension. Adding the priority later will require to bump the plugin version from 8 to 9, but this is ok. We will not run out of version numbers soon ;) The priority is only a "hint" to provide a reasonable default behavior without requiring any extra configuration by the user or some sort of GUI. |
if (trackLocation.isEmpty()) { | ||
return QImage(); | ||
} | ||
DEBUG_ASSERT(!trackLocation.isEmpty()); |
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.
Generally we should prefer DEBUG_ASSERT_AND_HANDLE.
DEBUG_ASSERT_AND_HANDLE(...) {
return QImage();
}
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.
Empty file names and non-existent files are handled gracefully by SoundSourceProxy, we don't need to handle these errors here again. Instead of handling it twice I would prefer to remove the DEBUG_ASSERT entirely.
Empty file names are handled gracefully by SoundSourceProxy.
|
||
#include "sources/soundsource.h" | ||
|
||
#include <QStringList> |
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.
Missing include for QUrl, QSharedPointer, QString
Thanks @uklotzde ! When Albert and I worked on the original plugin API we took care not to pass heap allocated objects across the DLL / binary boundary and free them on the other side. On Windows, this will cause immediate segfaults if the DLL and the binary are linked to different runtimes. You can see an example of this style with the old I notice that the 1.12 branch (pre-SS-refactor) commits a huge sin here by allocating the heap-allocated SoundSource itself in the plugin and freeing it in Mixxx so I think we've gotten sloppy over the years in this regard. I'm worried about the use of QSharedPointer/QStrings in this version of the API. When the DLL allocates a QSharedPointer/QString and passes it to the main Mixxx binary, I believe the code executing to handle that object is the Mixxx binary's copy of QString/QSharedPointer code. Correct me if I'm wrong! So when the QSharedPointer destructor runs, the Mixxx binary QSharedPointer destructor is what is actually running, which will free the SoundSourceProvider using the Mixxx heap, not the DLL heap. Have you given this any thought? |
@rryan As you mentioned I've seen that many resources are allocated on one side and freed on the other: The SoundSource itself, QString with metadata, QImage with cover art, .... Only doing it right for the file extensions didn't seem to make any sense to me?! So I assumed that this doesn't matter here. |
The C++ operators new and delete are now called symmetrically from within the external plugin libraries and should use the same C/C++ runtime. Unfortunately I'm not able to test if this works as expected for Windows DLLs. |
@rryan |
|
||
// Singleton: SoundSourceProviderM4A is stateless | ||
// and a single instance can safely be shared | ||
Mixxx::SoundSourceProviderM4A SOUNDSOURCE_PROVIDER; |
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.
static variables should be camel case and prefixed with s
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.
In general, we should avoid static variables in libraries.
Can't we make it a static local of Mixxx_SoundSourcePluginAPI_getSoundSourceProvider
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.
@daschuer Ok, using a static local variable is a viable option
I want to try to understand the issue. Here some thoughts, please correct me If I am wrong. I wonder how Qt can do this with implicit sharing lets say in QString. Is that correct? If yes, We can use Qt containers only, if the linked used QT dlls are compiled with the same memory model. This means we cannot switch the memory model if we (only hypothetically) split out the plug-in builds. Since we can't do this anyway, we do not need to worry about a different memory models. So we have finally no issues here, Right? |
@daschuer Both app and plugin must be linked against the same shared Qt DLL. Then alll internal invocations of operator new/delete in Qt classes use the same C++ runtime and match. What happens in this library stays in this library ;) We only need to take care of managed pointers. They have to be fed with the appropriate deleter upon construction. This ensures that operator delete from the plugin is called instead of that from the app. This approach should work even when the plugins are compiled separately. |
Thanks for clarifying! |
I'm considering the case where some external party releases a soundsource plugin DLL. I had been assuming they were statically linking their own version of Qt -- but I guess that's prone to causing other problems anyway so we may require that they dynamically link to Qt. If we accept that they have to dynamically link to Qt (so they are using our Qt DLLs once we load their DLL) -- then I agree the heap used for shared Qt objects will be the one we chose when we compiled Qt. |
Thanks for the changes @uklotzde! |
SoundSource Plugin API: Version 8
Fixes https://bugs.launchpad.net/mixxx/+bug/1452651
File names for SoundSource plugins were truncated at the first occurrence of '#' due to an implicit conversion from QString to QUrl.