1 /*
2  * plugin.h
3  * Copyright 2005-2013 Ariadne Conill, Yoshiki Yazawa, Eugene Zagidullin, and
4  *                     John Lindgren
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions, and the following disclaimer in the documentation
14  *    provided with the distribution.
15  *
16  * This software is provided "as is" and without any warranty, express or
17  * implied. In no event shall the authors be liable for any damages arising from
18  * the use of this software.
19  */
20 
21 #ifndef LIBAUDCORE_PLUGIN_H
22 #define LIBAUDCORE_PLUGIN_H
23 
24 #include <libaudcore/audio.h>
25 #include <libaudcore/export.h>
26 #include <libaudcore/plugins.h>
27 #include <libaudcore/tuple.h>
28 #include <libaudcore/vfs.h>
29 #include <libaudcore/visualizer.h>
30 
31 enum class AudMenuID;
32 struct PluginPreferences;
33 
34 /* "Magic" bytes identifying an Audacious plugin header. */
35 #define _AUD_PLUGIN_MAGIC ((int)0x8EAC8DE2)
36 
37 /* API version.  Plugins are marked with this number at compile time.
38  *
39  * _AUD_PLUGIN_VERSION is the current version; _AUD_PLUGIN_VERSION_MIN is
40  * the oldest one we are backward compatible with.  Plugins marked older than
41  * _AUD_PLUGIN_VERSION_MIN or newer than _AUD_PLUGIN_VERSION are not loaded.
42  *
43  * Before releases that add new pointers to the end of the API tables, increment
44  * _AUD_PLUGIN_VERSION but leave _AUD_PLUGIN_VERSION_MIN the same.
45  *
46  * Before releases that break backward compatibility (e.g. remove pointers from
47  * the API tables), increment _AUD_PLUGIN_VERSION *and* set
48  * _AUD_PLUGIN_VERSION_MIN to the same value. */
49 
50 #define _AUD_PLUGIN_VERSION_MIN 48 /* 3.8-devel */
51 #define _AUD_PLUGIN_VERSION 48     /* 3.8-devel */
52 
53 /* Default priority. */
54 #define _AUD_PLUGIN_DEFAULT_PRIO 5
55 
56 /* A NOTE ON THREADS
57  *
58  * How thread-safe a plugin must be depends on the type of plugin.  Note that
59  * some parts of the Audacious API are *not* thread-safe and therefore cannot be
60  * used in some parts of some plugins; for example, input plugins cannot use
61  * GUI-related calls or access the playlist except in about() and configure().
62  *
63  * Thread-safe plugins: transport, playlist, input, effect, and output.  These
64  * must be mostly thread-safe.  init() and cleanup() may be called from
65  * secondary threads; however, no other functions provided by the plugin will be
66  * called at the same time.  about() and configure() will be called only from
67  * the main thread.  All other functions provided by the plugin may be called
68  * from any thread and from multiple threads simultaneously.
69  *
70  * Exceptions:
71  * - Because many existing input plugins are not coded to handle simultaneous
72  *   calls to play(), play() will only be called from one thread at a time.  New
73  *   plugins should not rely on this exception, though.
74  * - Some combinations of calls, especially for output and effect plugins, make
75  *   no sense; for example, flush() in an output plugin will only be called
76  *   after open_audio() and before close_audio().
77  *
78  * Single-thread plugins: visualization, general, and interface.  Functions
79  * provided by these plugins will only be called from the main thread. */
80 
81 /* CROSS-PLUGIN MESSAGES
82  *
83  * Since 3.2, Audacious implements a basic messaging system between plugins.
84  * Messages are sent using aud_plugin_send_message() and received through the
85  * take_message() method specified in the header of the receiving plugin.
86  * Plugins that do not need to receive messages can set take_message() to
87  * nullptr.
88  *
89  * Each message includes a code indicating the type of message, a pointer to
90  * some data, and a value indicating the size of that data. What the message
91  * data contains is entirely up to the two plugins involved. For this reason, it
92  * is crucial that both plugins agree on the meaning of the message codes used.
93  *
94  * Once the message is sent, an integer error code is returned. If the receiving
95  * plugin does not provide the take_message() method, -1 is returned. If
96  * take_message() does not recognize the message code, it should ignore the
97  * message and return -1. An error code of zero represents success. Other error
98  * codes may be used with more specific meanings.
99  *
100  * For the time being, aud_plugin_send_message() should only be called from the
101  * program's main thread. */
102 
103 /* plugin flags */
104 enum
105 {
106     PluginGLibOnly = 0x1, // plugin requires GLib main loop
107     PluginQtOnly = 0x2    // plugin requires Qt main loop
108 };
109 
110 struct PluginInfo
111 {
112     const char * name;
113     const char * domain; // for gettext
114     const char * about;
115     const PluginPreferences * prefs;
116     int flags;
117 };
118 
119 class LIBAUDCORE_PUBLIC Plugin
120 {
121 public:
Plugin(PluginType type,PluginInfo info)122     constexpr Plugin(PluginType type, PluginInfo info) : type(type), info(info)
123     {
124     }
125 
126     const int magic = _AUD_PLUGIN_MAGIC;
127     const int version = _AUD_PLUGIN_VERSION;
128 
129     const PluginType type;
130     const PluginInfo info;
131 
init()132     virtual bool init() { return true; }
cleanup()133     virtual void cleanup() {}
134 
take_message(const char * code,const void * data,int size)135     virtual int take_message(const char * code, const void * data, int size)
136     {
137         return -1;
138     }
139 };
140 
141 class LIBAUDCORE_PUBLIC TransportPlugin : public Plugin
142 {
143 public:
TransportPlugin(const PluginInfo info,const ArrayRef<const char * > schemes)144     constexpr TransportPlugin(const PluginInfo info,
145                               const ArrayRef<const char *> schemes)
146         : Plugin(PluginType::Transport, info), schemes(schemes)
147     {
148     }
149 
150     /* supported URI schemes (without "://") */
151     const ArrayRef<const char *> schemes;
152 
153     virtual VFSImpl * fopen(const char * filename, const char * mode,
154                             String & error) = 0;
155 
test_file(const char * filename,VFSFileTest test,String & error)156     virtual VFSFileTest test_file(const char * filename, VFSFileTest test,
157                                   String & error)
158     {
159         return VFSFileTest(0);
160     }
161 
read_folder(const char * filename,String & error)162     virtual Index<String> read_folder(const char * filename, String & error)
163     {
164         return Index<String>();
165     }
166 };
167 
168 class LIBAUDCORE_PUBLIC PlaylistPlugin : public Plugin
169 {
170 public:
PlaylistPlugin(const PluginInfo info,const ArrayRef<const char * > extensions,bool can_save)171     constexpr PlaylistPlugin(const PluginInfo info,
172                              const ArrayRef<const char *> extensions,
173                              bool can_save)
174         : Plugin(PluginType::Playlist, info), extensions(extensions),
175           can_save(can_save)
176     {
177     }
178 
179     /* supported file extensions (without periods) */
180     const ArrayRef<const char *> extensions;
181 
182     /* true if the plugin can save playlists */
183     const bool can_save;
184 
185     /* path: URI of playlist file (in)
186      * file: VFS handle of playlist file (in, read-only file, not seekable)
187      * title: title of playlist (out)
188      * items: playlist entries (out) */
189     virtual bool load(const char * path, VFSFile & file, String & title,
190                       Index<PlaylistAddItem> & items) = 0;
191 
192     /* path: URI of playlist file (in)
193      * file: VFS handle of playlist file (in, write-only file, not seekable)
194      * title: title of playlist (in)
195      * items: playlist entries (in) */
save(const char * path,VFSFile & file,const char * title,const Index<PlaylistAddItem> & items)196     virtual bool save(const char * path, VFSFile & file, const char * title,
197                       const Index<PlaylistAddItem> & items)
198     {
199         return false;
200     }
201 };
202 
203 class LIBAUDCORE_PUBLIC OutputPlugin : public Plugin
204 {
205 public:
206     constexpr OutputPlugin(const PluginInfo info, int priority,
207                            bool force_reopen = false)
Plugin(PluginType::Output,info)208         : Plugin(PluginType::Output, info), priority(priority),
209           force_reopen(force_reopen)
210     {
211     }
212 
213     /* During probing, plugins with higher priority (10 to 0) are tried first.
214      */
215     const int priority;
216 
217     /* Whether close_audio() and open_audio() must always be called between
218      * songs, even if the audio format is the same.  Note that this defeats
219      * gapless playback. */
220     const bool force_reopen;
221 
222     /* Returns current volume for left and right channels (0 to 100). */
223     virtual StereoVolume get_volume() = 0;
224 
225     /* Changes volume for left and right channels (0 to 100). */
226     virtual void set_volume(StereoVolume volume) = 0;
227 
228     /* Sets information about the song being played.  This function will be
229      * called before open_audio(). */
set_info(const char * filename,const Tuple & tuple)230     virtual void set_info(const char * filename, const Tuple & tuple) {}
231 
232     /* Begins playback of a PCM stream.  <format> is one of the FMT_*
233      * enumeration values defined in libaudcore/audio.h.  Returns true on
234      * success. */
235     virtual bool open_audio(int format, int rate, int chans,
236                             String & error) = 0;
237 
238     /* Ends playback.  Any buffered audio data is discarded. */
239     virtual void close_audio() = 0;
240 
241     /* Waits until write_audio() will return a size greater than zero.
242      * get_delay(), pause(), and flush() may be called meanwhile; if flush()
243      * is called, period_wait() should return immediately. */
244     virtual void period_wait() = 0;
245 
246     /* Writes up to <size> bytes of data, in the format given to open_audio().
247      * If there is not enough buffer space for all <size> bytes, writes only as
248      * many bytes as can be written immediately without blocking.  Returns the
249      * number of bytes actually written. */
250     virtual int write_audio(const void * data, int size) = 0;
251 
252     /* Waits until all buffered data has been heard by the user. */
253     virtual void drain() = 0;
254 
255     /* Returns an estimate of how many milliseconds will pass before all the
256      * data passed to write_audio() has been heard by the user. */
257     virtual int get_delay() = 0;
258 
259     /* Pauses the stream if <p> is nonzero; otherwise unpauses it.
260      * write_audio() will not be called while the stream is paused. */
261     virtual void pause(bool pause) = 0;
262 
263     /* Discards any buffered audio data. */
264     virtual void flush() = 0;
265 };
266 
267 class LIBAUDCORE_PUBLIC EffectPlugin : public Plugin
268 {
269 public:
EffectPlugin(const PluginInfo info,int order,bool preserves_format)270     constexpr EffectPlugin(const PluginInfo info, int order,
271                            bool preserves_format)
272         : Plugin(PluginType::Effect, info), order(order),
273           preserves_format(preserves_format)
274     {
275     }
276 
277     /* Effects with lowest order (0 to 9) are applied first. */
278     const int order;
279 
280     /* If the effect does not change the number of channels or the sampling
281      * rate, it can be enabled and disabled more smoothly. */
282     const bool preserves_format;
283 
284     /* All processing is done in floating point.  If the effect plugin wants to
285      * change the channel count or sample rate, it can change the parameters
286      * passed to start().  They cannot be changed in the middle of a song. */
287     virtual void start(int & channels, int & rate) = 0;
288 
289     /* Performs effect processing.  process() may modify the audio samples in
290      * place and return a reference to the same buffer, or it may return a
291      * reference to an internal working buffer.  The number of output samples
292      * need not be the same as the number of input samples. */
293     virtual Index<float> & process(Index<float> & data) = 0;
294 
295     /* Optional.  A seek is taking place; any buffers should be discarded.
296      * Unless the "force" flag is set, the plugin may choose to override the
297      * normal flush behavior and handle the flush itself (for example, to
298      * perform crossfading).  The flush() function should return false in this
299      * case to prevent flush() from being called in downstream effect plugins.
300      */
flush(bool force)301     virtual bool flush(bool force) { return true; }
302 
303     /* Exactly like process() except that any buffers should be drained (i.e.
304      * the data processed and returned).  finish() will be called a second time
305      * at the end of the last song in the playlist. */
finish(Index<float> & data,bool end_of_playlist)306     virtual Index<float> & finish(Index<float> & data, bool end_of_playlist)
307     {
308         return process(data);
309     }
310 
311     /* Required only for plugins that change the time domain (e.g. a time
312      * stretch) or use read-ahead buffering.  translate_delay() must do two
313      * things: first, translate <delay> (which is in milliseconds) from the
314      * output time domain back to the input time domain; second, increase
315      * <delay> by the size of the read-ahead buffer.  It should return the
316      * adjusted delay. */
adjust_delay(int delay)317     virtual int adjust_delay(int delay) { return delay; }
318 };
319 
320 enum class InputKey
321 {
322     Ext,
323     MIME,
324     Scheme,
325     count
326 };
327 
328 class LIBAUDCORE_PUBLIC InputPlugin : public Plugin
329 {
330 public:
331     enum
332     {
333         /* Indicates that the plugin can write file tags */
334         FlagWritesTag = (1 << 0),
335 
336         /* Indicates that files handled by the plugin may contain more than one
337          * song.  When reading the tuple for such a file, the plugin should set
338          * the FIELD_SUBSONG_NUM field to the number of songs in the file.  For
339          * all other files, the field should be left unset.
340          *
341          * Example:
342          * 1. User adds a file named "somefile.xxx" to the playlist.  Having
343          * determined that this plugin can handle the file, Audacious opens the
344          * file and calls probe_for_tuple().  probe_for_tuple() sees that there
345          * are 3 songs in the file and sets FIELD_SUBSONG_NUM to 3.
346          * 2. For each song in the file, Audacious opens the file and calls
347          * probe_for_tuple(); this time, however, a question mark and song
348          * number are appended to the file name passed: "somefile.sid?2" refers
349          * to the second song in the file "somefile.sid".
350          * 3. When one of the songs is played, Audacious opens the file and
351          * calls play() with a file name modified in this way. */
352         FlagSubtunes = (1 << 1)
353     };
354 
355     struct InputInfo
356     {
357         typedef const char * const * List;
358 
359         int flags, priority;
360         aud::array<InputKey, List> keys;
361 
362         constexpr InputInfo(int flags = 0)
flagsInputInfo363             : flags(flags), priority(_AUD_PLUGIN_DEFAULT_PRIO), keys{}
364         {
365         }
366 
367         /* Associates file extensions with the plugin. */
with_extsInputInfo368         constexpr InputInfo with_exts(List exts) const
369         {
370             return InputInfo(flags, priority, exts, keys[InputKey::MIME],
371                              keys[InputKey::Scheme]);
372         }
373 
374         /* Associates MIME types with the plugin. */
with_mimesInputInfo375         constexpr InputInfo with_mimes(List mimes) const
376         {
377             return InputInfo(flags, priority, keys[InputKey::Ext], mimes,
378                              keys[InputKey::Scheme]);
379         }
380 
381         /* Associates custom URI schemes with the plugin.  Plugins using custom
382          * URI schemes are expected to handle their own I/O.  Hence, any VFSFile
383          * passed to play(), read_tuple(), etc. will be null. */
with_schemesInputInfo384         constexpr InputInfo with_schemes(List schemes) const
385         {
386             return InputInfo(flags, priority, keys[InputKey::Ext],
387                              keys[InputKey::MIME], schemes);
388         }
389 
390         /* Sets how quickly the plugin should be tried in searching for a plugin
391          * to handle a file which could not be identified from its extension.
392          * Plugins with priority 0 are tried first, 10 last. */
with_priorityInputInfo393         constexpr InputInfo with_priority(int priority) const
394         {
395             return InputInfo(flags, priority, keys[InputKey::Ext],
396                              keys[InputKey::MIME], keys[InputKey::Scheme]);
397         }
398 
399     private:
InputInfoInputInfo400         constexpr InputInfo(int flags, int priority, List exts, List mimes,
401                             List schemes)
402             : flags(flags), priority(priority), keys{exts, mimes, schemes}
403         {
404         }
405     };
406 
InputPlugin(PluginInfo info,InputInfo input_info)407     constexpr InputPlugin(PluginInfo info, InputInfo input_info)
408         : Plugin(PluginType::Input, info), input_info(input_info)
409     {
410     }
411 
412     const InputInfo input_info;
413 
414     /* Returns true if the plugin can handle the file. */
415     virtual bool is_our_file(const char * filename, VFSFile & file) = 0;
416 
417     /* Reads metadata and album art (if requested and available) from the file.
418      * The filename fields of the tuple are already set before the function is
419      * called.  If album art is not needed, <image> will be nullptr.  The return
420      * value should be true if <tuple> was successfully read, regardless of
421      * whether album art was read. */
422     virtual bool read_tag(const char * filename, VFSFile & file, Tuple & tuple,
423                           Index<char> * image) = 0;
424 
425     /* Plays the file.  Returns false on error.  Also see input-api.h. */
426     virtual bool play(const char * filename, VFSFile & file) = 0;
427 
428     /* Optional.  Writes metadata to the file, returning false on error. */
write_tuple(const char * filename,VFSFile & file,const Tuple & tuple)429     virtual bool write_tuple(const char * filename, VFSFile & file,
430                              const Tuple & tuple)
431     {
432         return false;
433     }
434 
435     /* Optional.  Displays a window showing info about the file.  In general,
436      * this function should be avoided since Audacious already provides a file
437      * info window. */
file_info_box(const char * filename,VFSFile & file)438     virtual bool file_info_box(const char * filename, VFSFile & file)
439     {
440         return false;
441     }
442 
443 protected:
444     /* Prepares the output system for playback in the specified format.  Also
445      * triggers the "playback ready" hook.  Hence, if you call set_replay_gain,
446      * set_playback_tuple, or set_stream_bitrate, consider doing so before
447      * calling open_audio.  There is no return value.  If the requested audio
448      * format is not supported, write_audio() will do nothing and check_stop()
449      * will immediately return true. */
450     static void open_audio(int format, int rate, int channels);
451 
452     /* Informs the output system of replay gain values for the current song so
453      * that volume levels can be adjusted accordingly, if the user so desires.
454      * This may be called at any time during playback should the values change.
455      */
456     static void set_replay_gain(const ReplayGainInfo & gain);
457 
458     /* Passes audio data to the output system for playback.  The data must be in
459      * the format passed to open_audio(), and the length (in bytes) must be an
460      * integral number of frames.  This function blocks until all the data has
461      * been written (though it may not yet be heard by the user). */
462     static void write_audio(const void * data, int length);
463 
464     /* Returns the current tuple for the stream. */
465     static Tuple get_playback_tuple();
466 
467     /* Updates the tuple for the stream. */
468     static void set_playback_tuple(Tuple && tuple);
469 
470     /* Updates the displayed bitrate, in bits per second. */
471     static void set_stream_bitrate(int bitrate);
472 
473     /* Checks whether playback is to be stopped.  The play() function should
474      * poll check_stop() periodically and return as soon as check_stop() returns
475      * true. */
476     static bool check_stop();
477 
478     /* Checks whether a seek has been requested.  If so, returns the position to
479      * seek to, in milliseconds.  Otherwise, returns -1. */
480     static int check_seek();
481 };
482 
483 class LIBAUDCORE_PUBLIC DockablePlugin : public Plugin
484 {
485 public:
DockablePlugin(PluginType type,PluginInfo info)486     constexpr DockablePlugin(PluginType type, PluginInfo info)
487         : Plugin(type, info)
488     {
489     }
490 
491     /* GtkWidget * get_gtk_widget () */
get_gtk_widget()492     virtual void * get_gtk_widget() { return nullptr; }
493 
494     /* QWidget * get_qt_widget () */
get_qt_widget()495     virtual void * get_qt_widget() { return nullptr; }
496 };
497 
498 class LIBAUDCORE_PUBLIC GeneralPlugin : public DockablePlugin
499 {
500 public:
GeneralPlugin(PluginInfo info,bool enabled_by_default)501     constexpr GeneralPlugin(PluginInfo info, bool enabled_by_default)
502         : DockablePlugin(PluginType::General, info),
503           enabled_by_default(enabled_by_default)
504     {
505     }
506 
507     const bool enabled_by_default;
508 };
509 
510 class LIBAUDCORE_PUBLIC VisPlugin : public DockablePlugin, public Visualizer
511 {
512 public:
VisPlugin(PluginInfo info,int type_mask)513     constexpr VisPlugin(PluginInfo info, int type_mask)
514         : DockablePlugin(PluginType::Vis, info), Visualizer(type_mask)
515     {
516     }
517 };
518 
519 class LIBAUDCORE_PUBLIC IfacePlugin : public Plugin
520 {
521 public:
IfacePlugin(PluginInfo info)522     constexpr IfacePlugin(PluginInfo info) : Plugin(PluginType::Iface, info) {}
523 
524     virtual void show(bool show) = 0;
525     virtual void run() = 0;
526     virtual void quit() = 0;
527 
528     virtual void show_about_window() = 0;
529     virtual void hide_about_window() = 0;
530     virtual void show_filebrowser(bool open) = 0;
531     virtual void hide_filebrowser() = 0;
532     virtual void show_jump_to_song() = 0;
533     virtual void hide_jump_to_song() = 0;
534     virtual void show_prefs_window() = 0;
535     virtual void hide_prefs_window() = 0;
536     virtual void plugin_menu_add(AudMenuID id, void func(), const char * name,
537                                  const char * icon) = 0;
538     virtual void plugin_menu_remove(AudMenuID id, void func()) = 0;
539 
startup_notify(const char * id)540     virtual void startup_notify(const char * id) {}
541 };
542 
543 #endif
544