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