Help - Search - Members - Calendar
Full Version: Caching information about playlists
Hydrogenaudio Forums > Hosted Forums > foobar2000 > Development - (fb2k)
mixcherry
I'd like to create entrypoint service that would "cache" some information about playlists. This cache should be invalidated on certain playlist callback events (on_items_added/on_items_removed).

To achieve this, I should auto-register my playlist_callback somewhere in my entrypoint service implementation (e.g. using static_api_ptr_t<playlist_manager>()->register_callback(...)). AFAIK, this is not possible.

I'm thinking about extending playlist_manager (class my_playlist_cache : public playlist_manager). Is extending playlist_manager class a good idea? Does it violate any rules? Or are there better ways to achieve my goal?
Frank Bicking
playlist_manager is implemented by the core and should never be reimplemented.

Implement the playlist_callback_static or playlist_callback_single_static entrypoint service, and register it using one of the service_factory_single templates.
mixcherry
Thank you. I've extended playlist_callback_static with my method:
CODE
class NOVTABLE cache : public playlist_callback_static {
public:
    virtual int get_value(t_size playlist) = 0;
    FB2K_MAKE_SERVICE_INTERFACE(cache, playlist_callback_static);
};

I've implemented this class (class cache_impl : public cache) and registered it using static service_factory_single_t<cache_impl> g_cache_impl_factory;.

How can I access my service now?

I've been trying service_enum_t<cache> e; service_ptr_t<cache> ptr; while(e.next(ptr)) ptr->get_value();
and static_api_ptr_t<cache> api;
but both methods result in compiler error: service.h(423) : error C2514: 'pfc::assert_same_type<p_type1,p_type2>' : class has no constructors
Frank Bicking
service_enum_t only works with entrypoint classes - you would have to enumerate playlist_callback_static and call service_query_t() on each pointer to test if it implements the cache interface. Actually, standard_api_create_t which is used in static_api_ptr_t does that for you, so your second line should actually work.

But considering that implementations working with your cache would never want to call playlist_callback methods such as on_items_added() on their own, maybe deriving directly from playlist_callback_static wasn't such a good idea after all.

How about this:

CODE
class NOVTABLE cache : public service_base {
public:
    virtual int get_value(t_size playlist) = 0;
    FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(cache);
};

Usage would be the same as in your examples, using enumeration or static_api_ptr_t, depending on how many implementations you have.

The implementation would look like this:

CODE
class cache_impl : public cache {
    int get_value(t_size playlist);
public:
    // Do whatever is necessary to update your cached content.
    void on_items_added(t_size p_playlist, t_size p_start, metadb_handle_list_cref p_data, const bit_array & p_selection);
    // Implement other playlist_callback methods here.
};

static service_factory_single_transparent_t<cache_impl> g_cache_impl;

With a helper class that implements playlist_callback_static and forwards relevant callbacks to your cache implementation:

CODE
class cache_playlist_callback : public playlist_callback_static {
    unsigned get_flags() { return flag_all; }
    void on_items_added(t_size p_playlist, t_size p_start, metadb_handle_list_cref p_data, const bit_array & p_selection) { g_cache_impl.on_items_added(p_playlist, p_start, p_data, p_selection); }
    // Repeat for other playlist_callback methods. Some may do nothing.
};

// Uncomment when done.
// static service_factory_single_t<cache_playlist_callback> g_cache_playlist_callback;

Hope this helps.
Yirkha
Maybe not relevant to what you want to do in the end, but note there is also API for associating user data with playlists, see playlist_manager_v2::playlist_set_runtime_property() and other functions.
mixcherry
@Yirkha, yes, I know about runtime playlist properties. And I hope reading them inside my entrypoint service implementation is not another breaking of some rules as long as service methods are called from the main thread.

@Frank Bicking - thank you very much, you've helped me a lot! However, one thing comes to my mind now. I have this helper static callback used in my entrypoint service that invalidates cache - cache_invalidator_callback. But I also have another callback used in my component (registered/unregistered on component's show/hide) that redraws my window on certain playlist actions (e.g. on_items_added) - window_refresher_callback.

Can it be somehow guaranteed that my cache_invalidator_callback events will be always called before window_refresher_callback? Because if it can't be guaranteed, then this cache class is useless :/ I suppose that now static callback events have precedence over registered callback events (they are added earlier to callbacks list (?)), but it is not mentioned anywhere in the SDK to be guaranteed.
foosion
There is no guaranteed order for calling callbacks. If you need to make sure that your cache is updated before the code that uses the cache, then one way would be too have the cache forward the callback to the other code after its has updated itself. Of course, your cache service would then have to provide methods for registering playlist_callbacks. This also won't work with code that uses playlist_callback_static and your cache service.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2009 Invision Power Services, Inc.