HydrogenAudio

Hosted Forums => foobar2000 => Development - (fb2k) => Topic started by: TheQwertiest on 2019-01-23 14:38:12

Title: fb2k API questions
Post by: TheQwertiest on 2019-01-23 14:38:12
@Peter , could you help with the following, please?

1. playlist_manager_v4::create_playlist_ex / playlist_manager_v4::create_playlist_ex: in which case can it return pfc_infinite? Is it more like paranoia check (i.e. assert would suffice) or should I always validate it?
2. What is assigned to the return value of playlist_manager::playlist_insert_items? Is it the new position of the first track (i.e. same as p_base argument)?
3. Is there any difference between using u* methods from shared.dll and using corresponding WinAPI methods? E.g. uCreateFile vs CreateFile

Thanks in advance =)
Title: Re: fb2k API questions
Post by: Peter on 2019-01-23 19:21:54
1.
Playlist creation will fail if called from an illegal context - wrong thread, called from a global callback, fb2k shutdown in progress.
If your code already ensures running in main thread, an assert check should be sufficient.
You cannot call any methods that alter the state of playback, playlist, etc from a global callback - such as playlist/playback/etc callback - because the method by itself dispatches callbacks, which cannot be done recursively.
2.
Returned value from playlist_insert_items is the index of the first inserted track - or pfc_infinite on failure (conditions above or an autoplaylist that refuses insertions).
3.
u* methods used to be relevant when Win9X was still supported - Win9X users got a different build of the DLL which called non-Unicode APIs. By now there's no difference. These methods are mainly retained for backwards compatibility. Though you can sometimes reduce the size of your component by calling them instead of converting UTF-8 to wchar_t by yourself.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-01-24 12:12:02
Thanks!

1.
Playlist creation will fail if called from an illegal context - ... fb2k shutdown in progress ...
Am I right to assume that this condition won't be triggered until after initquit::on_quit callback is executed?

And another small question:
Can autoplaylist_manager::add_client_simple(p_query, p_sort, p_playlist, p_flags) fail on a newly created playlist?
Title: Re: fb2k API questions
Post by: Peter on 2019-01-24 16:56:40
If your component creates playlist in direct response to user events, it is safe to assume that shutdown is not yet in progress.
initquit::on_quit() is one way to know about shutdown in progress, but if some other component decides to do stuff that triggers your code in their on_quit(), your on_quit() might not yet have executed.

autoplaylist_manager::add_client_simple() on a newly created playlist should never fail. The current implementation throws an exception if the specified playlist index is invalid, or if the playlist is already an autoplaylist, neither of which can be true in your case.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-01-27 21:16:52
Thanks for all the answers!

PS: It appears that add_client_simple may also fail when the query is incorrect (e.g. `PRESENT ALL`).
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-04-20 22:22:17
@Peter, a small fb2k API question: is modal_dialog_scope::can_create() thread-safe? (shared.h)
Thanks in advance!
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-04-25 17:57:56
If anyone stumbles on the question above: judging by disassembly, it seems that modal_dialog_scope::can_create() always returns false when invoked on non-main thread.
Title: Re: fb2k API questions
Post by: Peter on 2019-06-17 11:11:05
Everything modal dialog related should only ever be called from main thread.

modal_dialog_scope::can_create() returns false when either called from a non main thread or there already is a known modal dialog running.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-06-17 11:40:34
Figured as much, thanks!
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-07-15 10:45:33
@Peter, another small API question =)
What's the purpose of modal_dialog_scope? Is it purely a FYI method (i.e. indication that it would be possible to create a modal dialog)? Is it safe to invoke a modal dialog without wrapping it's call in modal_dialog_scope?
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-07-19 14:19:22
And another question: what is the correct way for a component to generate a dynamic main menu (i.e. so that it could be changed after component initialization)? There is such menu for playlists ('View>Switch to playlist'), but I'm not sure how to achieve that....

I've found 'mainmenu_commands_v2' which might be what I need: there is a `mainmenu_commands_v2::dynamic_execute` method which accepts subId GUID, but should this GUID be distinct from all the other menu GUIDs? If so, then should I run a check against already defined GUIDs every time I add a new menu item?
Title: Re: fb2k API questions
Post by: Peter on 2019-07-19 14:38:04
modal_dialog_scope exists to prevent accidental creation of another modal dialog while a modal dialog is already in progress. Execution of various fb2k menu commands is not blocked during a modal dialog, but you can at least know that there's a modal dialog in progress and refuse to create another one - which could lead to modal dialogs getting dismissed out of order or worse.

Dynamic mainmenu commands will be added to foo_sample.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-07-19 14:49:24
Thanks for the answers!

modal_dialog_scope exists to prevent accidental creation of another modal dialog while a modal dialog is already in progress. Execution of various fb2k menu commands is not blocked during a modal dialog, but you can at least know that there's a modal dialog in progress and refuse to create another one - which could lead to modal dialogs getting dismissed out of order or worse.
Hm... So that means that it is actually *required* for the component to wrap every modal dialog creation call. I think it would be nice to add this to 'modal_dialog_scope' documentation =)

Dynamic mainmenu commands will be added to foo_sample.
Thanks!
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-07-22 12:30:26
Aaaand another one:
Is it possible to disable `space` key handling by fb2k in DUI so that it could be passed (and handled) by panel? E.g. user wants to enter some text.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-08-23 12:21:00
@Peter: another question, if you don't mind =) What is the proper way to execute API action that requires initialized fb2k?

Example scenario #1: I want to show popup via `popup_message::g_show` during CUI panel creation (which happens before component's `on_init` is called). If invoked before fb2k is initialized, no popup will show up.

Example scenario #2: invocation timing is the same as above, but I need fb2k handle (via `core_api::get_main_window()`). This handle will be nullptr if requested before fb2k initialization.

Current workaround: queue all required action and execute them in the component's `on_init` callback.
Other workaround: queue actions via `fb2k::inMainThread` (this uses message queue probably, which activates only after fb2k initialization).

PS: The question above (https://hydrogenaud.io/index.php/topic,117208.msg973490.html#msg973490) is still relevant =)
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-11-29 12:04:19
@Peter, another small question (that's slightly similar to the one above):
Am I correct to assume that init_stage_callback::on_init_stage(init_stages::after_ui_init) will be called after *all* components have been initialized?
Title: Re: fb2k API questions
Post by: Peter on 2019-11-29 12:29:45
Sounds like CUI panel creation occurs when there's no known main window yet. Apparently the popup_message code doesn't like that - does nothing instead of creating a parentless (toplevel) dialog.

initquit::on_init() gets called when everything's initialized, main window has been created and all other APIs are valid to call.
init_stage_callback::on_init_stage(init_stages::after_ui_init) gets called just before initquit::on_init().

In general, fb2k::inMainThread() should work for deferring problematic API calls.
Or, check if core_api::get_main_wiindow() returns null; if so, store the messages and show popups from initquit::on_init().

Not sure what you mean about space key handling, embedded Album List in Default UI can take space key in its editbox just fine?

Neat trick with the [font] for code bits, I'll have to remember that one
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-11-29 13:04:29
Thanks for all the answer! Really appreciated!

Not sure what you mean about space key handling, embedded Album List in Default UI can take space key in its editbox just fine?
You are absolutely right: this is a bug/feature in my code... Sorry for the confusion >_<

Neat trick with the [font] for code bits, I'll have to remember that one
I was just too used to being able to inline `code blocks` in markdown. Thankfully, Google knew the answer =)
Title: Re: fb2k API questions
Post by: TheQwertiest on 2019-11-29 14:03:20
@Peter, the problem is that initquit::on_init in one component might be called before the initquit::on_init in another component.
E.g. my component is already up (initquit::on_init was called) and tries to use another component, which is not yet loaded completely (have yet to handle initquit::on_init).
Is there a callback (or maybe a bool check, which would be harder to abuse by component devs) to verify that fb2k has loaded all components (invoked all initquit::on_init callbacks) and thus it's safe to call any component?
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-15 12:43:19
@Peter, another day - another API question =)
Does API guarantee that input implemented with `input_factory_t` will not be called before `initquit::on_init` and after `innitquit::on_quit` (all implemented in the same component)?
Title: Re: fb2k API questions
Post by: Peter on 2020-08-17 20:20:49
No guarantees about inputs being called before on_init() or after on_quit().
Better just init on first use (std::call_once) and never deinit - only make sure all worker threads exit before process exits.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-18 11:13:08
Thanks for the answer!
Another small question: is it possible to get the metadb of the next track? I mean not 'next track in playlist', but the actual track that will be played next. Scenario: pre-loading the next track (if needed) to avoid hiccups.
Title: Re: fb2k API questions
Post by: Peter on 2020-08-18 12:08:32
Next track info is not currently available. Decision on what to play next (random etc) is made at the point decoding of the previous track has EOF'd, so the info doesn't physically exist until the track needs to start decoding.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-18 12:35:09
Darn... That's a shame... Thanks!
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-19 17:01:18
Aaaand another few small questions =)
1. Is it possible to create a custom auto-playlist, i.e. an auto-playlist that is managed by component?
Scenario: Spotify (a music streaming service) provides a playlist interface via an url. So ideally, a user could pass such link to the component, which would create an playlist that would be periodically synchronized with the Spotify service.

2. Is it possible to import multiple files via a single `File` > `Add location`? I.e. not as a single track with subsongs (`input_factory_t`), but as multiple separate tracks?
Scenario: same as above - an import of Spotify playlist.

Thanks in advance =)
Title: Re: fb2k API questions
Post by: fbuser on 2020-08-19 17:57:46
1. Is it possible to create a custom auto-playlist, i.e. an auto-playlist that is managed by component?
Scenario: Spotify (a music streaming service) provides a playlist interface via an url. So ideally, a user could pass such link to the component, which would create an playlist that would be periodically synchronized with the Spotify service.
Considering that the component is responsible for periodically populating the playlist, you can easily reproduce such a scenario, if you set a playlist lock (playlist.h, playlist_lock) to the target playlist, which will be only deactivated during populating the playlist.
Title: Re: fb2k API questions
Post by: Peter on 2020-08-20 20:27:33
Autoplaylists are internally implemented via playlist locks. It's not that pretty but works.

Current autoplaylist API only filters Media Library content, rather than providing its own content.

Re: Add Location - it's meant for remote resources... subsongs are not supported for such in general. You'd have to parse the location as a playlist instead.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-23 13:35:21
@fbuser , @Peter , thanks for the answers!

Considering that the component is responsible for periodically populating the playlist (...)

But is it possible to somehow `assign` a playlist to the component? I would not want to edit a random user-playlist if they decide to name it the same as component-managed-playlist =)

You'd have to parse the location as a playlist instead.
Could you, plz, point to the appropriate API for that?
Title: Re: fb2k API questions
Post by: fbuser on 2020-08-23 14:25:06
But is it possible to somehow `assign` a playlist to the component? I would not want to edit a random user-playlist if they decide to name it the same as component-managed-playlist =)
Yes, you could mark that playlist with playlist_manager_v2::playlist_set_property() so you can distinguish this playlist from a user-playlist with the same name.
Title: Re: fb2k API questions
Post by: marc2k3 on 2020-08-24 06:18:38
Could you, plz, point to the appropriate API for that?

You already have this implemented as plman.AddLocations in SMP using process_locations_notify and playlist_incoming_item_filter_v2 - >process_locations_async
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-24 13:25:48
@snotlicker , I'm not sure that these are applicable for my case: AFAIK these are used to handle callbacks *after* `FIle`>`Add location...` was invoked. And in my scenario I need to override the default behaviour of `Add location...` to generate the list of items first.

I've found `playlist_loader` API which looks exactly like the thing I need, but it doesn't work reliably for all cases and it can't handle arbitrary strings. E.g. `https://open.spotify.com/playlist/191UV79Bhgy1mBJOVfIpeS` fails with error `Object not found` for some reason. While `https://open.spotify.com/album/06bbY7KesJd8be5vQOMBxw` works fine :\
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-24 18:41:36
Oh and thank you @fbuser for the tips =)
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-24 18:55:31
@Peter , would it be possible to make `playlist_loader` receive a path even if it's not recognized by fb2k? E.g. pass smth like `unrecognized` to `playlist_loader::is_our_content_type()`
Title: Re: fb2k API questions
Post by: marc2k3 on 2020-08-24 19:05:22
The previous component was able to differentiate the different url types here??

https://github.com/stengerh/foo_input_spotify/blob/master/foo_input_spotify/input_spotify.cpp#L103L117

I guess libspotify did all the work but for whatever reason, the user playlist handling is borked while track/album urls load just fine. Isn't this where you need to step and in and make your web request to the spotify API and generate a list of track urls which libspotify can then open/play??
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-24 19:14:47
The previous component implemented everything via `input` interface: `album` and `playlist` objects would be handled as a multi-track file (like CUE files). Such behaviour has a lot of limitations, that's why I'm trying to use `playlist` interface instead and use `input` only for single tracks.

Isn't this where you need to step and in and make your web request to the spotify API and generate a list of track urls which libspotify can then open/play??
That's actually what I'm trying to do =)
It's all fine and dandy for `album` urls, but for some reason fb2k discards spotify `playlist` urls, making it impossible to generate a playable item set... There are no such limitations for `input` interface though.
Title: Re: fb2k API questions
Post by: marc2k3 on 2020-08-24 19:31:09
Add your own main menu entry/input box. Now you have full control over how urls are handled.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-25 14:00:33
Add your own main menu entry/input box.
That's my Plan B =)
But I would rather use (and integrate in) standard fb2k interface as much as possible.
Title: Re: fb2k API questions
Post by: kode54 on 2020-08-26 01:23:18
Then you won't be able to take over arbitrary URLs. For the standard Open Location prompt, you can only control either whole schemas, or the MIME type that the server returns when the file is retrieved using foobar's built-in HTTP/S handler.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-26 10:52:12
you can only control either whole schemas
Sorry, I don't understand what you mean by that (most likely due my lack of knowledge). `MIME type` is controlled via playlist_loader::is_our_content_type. Is there a similar interface to handle the `schema` (w/e it means in this context)?

(...)when the file is retrieved using foobar's built-in HTTP/S handler.
Any tips why this handler would reject a valid url?
Title: Re: fb2k API questions
Post by: kode54 on 2020-08-27 00:57:30
It accepts it, if it understands what file type it is. You have to register a playlist handler that accepts the exact MIME type your file returns. Otherwise, it will reject it.

Also, if it requires a login, there's no way to pass the login cookie or session to the URL handler, because every URL request handled this way explicitly passes zero cookies and only the exact information contained within the URL string.

As for the schema, you would have to register your own filesystem handler for a new protocol name, something like httpspotify or whatever, and you'd have to handle your own URL requests, or forward them to the existing https handler by modifying the URL and opening it directly yourself.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-27 09:27:52
Thanks for the info!
I've tried fetching the Spotify playlist url via curl with a plain GET request and it does indeed return a 404 error for some reason (it is accessible in browser without logging in though)... Not sure what's the deal with that (and why it works in browser), but it's clearly not the fault of fb2k.

As for the schema, you would have to register your own filesystem handler for a new protocol name
Would it work properly if I implement a new handler that tries to handle `http(/s)`? I.e. would it conflict with the built-in one? Or would such approach be not recommened/too hacky/error-prone/unstable or w/e?
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-27 09:48:32
Darn... This problem affects drag-n-drop functionality as well: if the GET request for the link returns 404, fb2k prevents further item processing with "Object not found" message =(
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-08-27 12:21:56
I've figured it out why URL returns 404: it requires a proper user agent header (e.g. "User-Agent: Firefox/79.0").
Google says there are quite a few of websites that refuse to work (by returning 404) with empty or non-browser-specific user-agents...

@Peter , @kode54 , would it be possible to attach some user agent when resolving links? (perhaps configurable via Advanced Preferences)
Title: Re: fb2k API questions
Post by: TheQwertiest on 2020-10-24 17:34:41
@Peter,
another small question =)

Scenario:
- component has a custom `input_impl` implemented.
- user requests properties of multiple tracks (e.g. via selecting all those tracks and ALT-Enter).
- `input_impl::open` is called.

Questions:
- Is there any interface/callback/etc that would make it possible to process multiple tracks at once instead of one by one?
- If not, is it possible to force these to be executed parallely? I.e. several threads that would call `input_impl::open` simultaneously, so that it would be possible to batch requests manually inside the `input_impl::open` implementation.

Reason:
Operations performed in this custom `input_impl::open` are pretty slow, but they can be performed in batch for multiple tracks at the same cost as a single track.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2021-09-26 17:34:15
@Peter, another small question: is it possible to add component in run-time? At least for the purpose of updates and stuff in the components settings section.

Scenario: a C++ component is used as a host/loader/proxy for .NET components (I doubt there will be more than one though xD). Everything SDK related (callback registration and etc) is handled by the host C++ component. But I want users to be able to interact just as usual even with said .NET components (check for updates/add/delete and etc).
Title: Re: fb2k API questions
Post by: kode54 on 2021-09-28 01:57:15
Probably not, for the same reason it's currently not possible to remove a component at run-time. All callback services must finish executing and be removed from registration. All input services currently decoding files must be removed from registration and cease operation. Basically every service that could be registered must be released by every other still-running service so it isn't referenced again. And things like initquit services must be called to simulate app shutdown for that component, in case the component relies on it for things like saving configuration.

Component configuration variables must also be serialized for saving on shutdown and removal of the component as well.

In the current SDK design, the player literally has no idea what components a particular service belongs to. And it completely randomizes the order of that global service table on every startup, to provoke possible race conditions from components that expect a deterministic load order to work.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2021-09-30 11:54:34
@kode54 , thanks for the answer!
I've found that it's possible to at least display such "external" components in Preferences components tab (like this >url (https://github.com/TheQwertiest/foo_title/blob/deeece65764ce21837cbafbce56ca35e9635dddc/foo_dotnet_component_host/fb2k/component_registration.cpp)<). Do you think that the version update check will work if I add those components to the fb2k component repo? I.e. without automatic download/update/removal, just the version check so that users can be notified when new version appears.

Since I'd rather avoid reimplementing fb2k component manager as much as possible :D
Title: Re: fb2k API questions
Post by: kode54 on 2021-10-01 00:01:11
The app does report newer component releases from the repository, but I don't know if it can simply open a web page with updates for newer versions if only a link is supplied, or if it requires an explicit package to be uploaded to the site.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2021-10-01 11:44:04
Guess I'll have to find out by experimenting =)
Title: Re: fb2k API questions
Post by: TheQwertiest on 2022-06-18 15:27:56
@Peter, a small API question: is >http client interface< (https://github.com/TheQwertiest/foobar2000-sdk/blob/master/SDK/http_client.h) thread-safe? I.e. can it be called from different threads without additional synchronization?
Title: Re: fb2k API questions
Post by: Peter on 2022-06-20 20:08:53
The http_client object is just an entrypoint for creating request objects so you can call http_client::get()->create_request(...) it from any thread you like.
Individual request and reply objects are not thread safe, that is you should synchronize if you want to call methods of the same object from different threads, which probably isn't what you want as I have no idea why anyone would do such thing.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2022-06-20 21:31:48
I was thinking of off-loading web access to a worker thread, so this works out nicely for me =)
Thanks!

A similar question, but regarding album_art_extractor_instance::query and album_art_extractor_instance_v2::query_paths (>link< (https://github.com/TheQwertiest/foobar2000-sdk/blob/master/SDK/album_art.h#L202)). Can it be used safely off the main thread as well?
Title: Re: fb2k API questions
Post by: marc2k3 on 2022-06-21 11:12:34
Your async album art methods in SMP inherited from JSP and originally WSH panel are already doing that.
Title: Re: fb2k API questions
Post by: Peter on 2022-06-21 14:48:52
If something takes an abort_callback&, it's designed for use in worker threads.

I'm cleaning the documentation up, I'll add info about all these.

I know it's not a pretty way of determining what is safe to call and what isn't, but I made most of main-thread-only-by-design functions crash/bugcheck if called from another thread.
Title: Re: fb2k API questions
Post by: TheQwertiest on 2022-06-22 12:44:10
If something takes an abort_callback&, it's designed for use in worker threads.
Nice! Now I don't have to bug you about each and every API point :D
Thanks =)

Your async album art methods in SMP inherited from JSP and originally WSH panel are already doing that.
Right! That's what I get for not servicing my code for too long...