Foobar2000:Development:Services

From Hydrogenaudio Knowledgebase


Services

A service type is an interface class, deriving directly or indirectly from service_base class. A service type class must not have any data members; it can only provide virtual methods (to be overridden by service implementation), helper non-virtual methods built around virtual methods, static helper methods, and constants / enums. Each service interface class must have a static class_guid member, used for identification when enumerating services or querying for supported functionality. A service type declaration should declare a class with public virtual/helper/static methods, and use FB2K_MAKE_SERVICE_INTERFACE() / FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT() macro to implement standard service behaviors for the class; additionally, class_guid needs to be defined outside class declaration (e.g. const GUID someclass::class_guid = {….}; ). Note that most of components will not declare their own service types, they will only implement existing ones declared in the SDK.

A service implementation is a class derived from relevant service type class, implementing virtual methods declared by service type class. Note that service implementation class does not implement virtual methods declared by service_base; those are implemented automatically.

You cannot directly instantiate a service implementation object because it's still missing virtual methods of service_base.

class myworker : public threaded_process_callback { /* threaded_process_callback methods overridden here */ };
auto obj = new myworker; // error
auto obj = fb2k::service_new<myworker>(); // good
service_ptr_t<myworker> obj = new service_impl_t<myworker>; // longer equivalent of fb2k::service_new<>, commonly used in older code, not auto-friendly

fb2k::service_new<> takes care of implementing common methods (service_base) needed by all services and returns an autopointer object that manages reference counting for you.

Note that service_base methods:

  • service_add_ref()
  • service_release()
  • service_query()

... are only intended for autopointer classes and should never be called directly in your code.

See also: Auto Pointers

Entrypoint services

An entrypoint service type is a special case of a service type that can be registered using service_factory templates, and then accessed from any point of service system (excluding DLL startup/shutdown code, such as code inside static object constructors/destructors). An entrypoint service type class must directly derive from service_base.

Registered entrypoint services can be accessed using:

  • For services types with variable number of implementations registered:
  • enumerate() static methods of the service class>
for( auto ptr : someclass::enumerate() ) { /* do stuff with ptr */ }
  • Or, service_enum_t<>, commonly used in older code:
service_enum_t<someclass> e; service_ptr_t<someclass> ptr; while(e.next(ptr)) ptr->dosomething();
  • For services types with a single always-present implementation registered - such as core services like playlist_manager - using someclass::get(), e.g.:
auto api = someclass::get(); api->dosomething(); api->dosomethingelse();

Using per-service-type defined static helper functions, e.g. someclass::g_dosomething() - those use relevant service enumeration methods internally. An entrypoint service type must use FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT() macro to implement standard entrypoint service behaviors, as opposed to all other service types that use FB2K_MAKE_SERVICE_INTERFACE() macro instead.

You can register your own entrypoint service implementations using FB2K_SERVICE_FACTORY() macro. It creates a static instance of your object and makes it available for everyone else to enumerate and access. Some services need to be registered differently, see documentation of individual services for details.

A typical entrypoint service implementation looks like this:

class myinitquit : public initquit {
public:
	void on_init() override {};
	void on_quit() override {};
};
FB2K_SERVICE_FACTORY(myinitquit);

Examples of entrypoint services

initquit, init_stage_callback

  • Implemented by: everyone.
  • Called by: core, on app startup and shutdown.

input_entry

  • Implemented by: decoder components.
  • Called by: everyone decoding audio files.
  • This service is not implemented directly, but with help of input_factory_t<> templates that implement all input services using your supplied class.

playlist_loader

  • Implemented by: core (standard playlist format), you (if you want to add your own playlist format).
  • Called by: any code loading or saving a playlist file.

popup_message

  • Implemented by: core. Do not reimplement!
  • Called by: everyone.