Audacious
$Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
00001 /* 00002 * Audacious: A cross-platform multimedia player 00003 * Copyright (c) 2007 Ben Tucker 00004 * Copyright 2009-2010 Audacious development team 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; under version 3 of the License. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses>. 00017 * 00018 * The Audacious team does not consider modular code linking to 00019 * Audacious or using our public API to be a derived work. 00020 */ 00021 00022 #include "config.h" 00023 00024 #include <glib.h> 00025 #include <dbus/dbus.h> 00026 #include <dbus/dbus-glib.h> 00027 #include <dbus/dbus-glib-bindings.h> 00028 #include <dbus/dbus-glib-lowlevel.h> 00029 #include "dbus.h" 00030 #include "dbus-service.h" 00031 #include "dbus-server-bindings.h" 00032 00033 #include <math.h> 00034 #include <libaudcore/eventqueue.h> 00035 00036 #include "audconfig.h" 00037 #include "debug.h" 00038 #include "drct.h" 00039 #include "equalizer.h" 00040 #include "main.h" 00041 #include "playback.h" 00042 #include "playlist.h" 00043 #include "interface.h" 00044 00045 struct StatusRequest 00046 { 00047 gboolean playing, paused; 00048 gint time, length; 00049 gint bitrate, samplerate, channels; 00050 }; 00051 00052 struct PositionRequest 00053 { 00054 gint playlist; /* -1 = active, -2 = playing */ 00055 gint entry; /* -1 = current */ 00056 gint entry_count, queue_count; 00057 }; 00058 00059 struct InfoRequest 00060 { 00061 gint playlist; /* -1 = active, -2 = playing */ 00062 gint entry; /* -1 = current */ 00063 gchar *filename, *title, *pltitle; 00064 gint length; 00065 }; 00066 00067 struct FieldRequest 00068 { 00069 gint playlist; /* -1 = active, -2 = playing */ 00070 gint entry; /* -1 = current */ 00071 const gchar *field; 00072 GValue *value; 00073 }; 00074 00075 struct AddRequest 00076 { 00077 gint position; /* -1 = at end */ 00078 gchar *filename; 00079 gboolean play; 00080 }; 00081 00082 struct MprisMetadataRequest 00083 { 00084 gint playlist; /* -1 = active, -2 = playing */ 00085 gint entry; /* -1 = current */ 00086 GHashTable *metadata; 00087 }; 00088 00089 static DBusGConnection *dbus_conn = NULL; 00090 static guint signals[LAST_SIG] = { 0 }; 00091 static guint tracklist_signals[LAST_TRACKLIST_SIG] = { 0 }; 00092 00093 static GThread *main_thread; 00094 static GMutex *info_mutex; 00095 static GCond *info_cond; 00096 00097 G_DEFINE_TYPE (RemoteObject, audacious_rc, G_TYPE_OBJECT) 00098 G_DEFINE_TYPE (MprisRoot, mpris_root, G_TYPE_OBJECT) 00099 G_DEFINE_TYPE (MprisPlayer, mpris_player, G_TYPE_OBJECT) 00100 G_DEFINE_TYPE (MprisTrackList, mpris_tracklist, G_TYPE_OBJECT) 00101 00102 #define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) 00103 00104 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList *obj); 00105 00106 void audacious_rc_class_init(RemoteObjectClass * klass) 00107 { 00108 } 00109 00110 void mpris_root_class_init(MprisRootClass * klass) 00111 { 00112 } 00113 00114 void mpris_player_class_init(MprisPlayerClass * klass) 00115 { 00116 signals[CAPS_CHANGE_SIG] = g_signal_new("caps_change", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); 00117 signals[TRACK_CHANGE_SIG] = 00118 g_signal_new("track_change", 00119 G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, DBUS_TYPE_G_STRING_VALUE_HASHTABLE); 00120 signals[STATUS_CHANGE_SIG] = 00121 g_signal_new("status_change", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_VALUE_ARRAY); 00122 } 00123 00124 void mpris_tracklist_class_init(MprisTrackListClass * klass) 00125 { 00126 tracklist_signals[TRACKLIST_CHANGE_SIG] = g_signal_new("track_list_change", G_OBJECT_CLASS_TYPE(klass), 00127 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); 00128 } 00129 00130 void audacious_rc_init(RemoteObject * object) 00131 { 00132 GError *error = NULL; 00133 DBusGProxy *driver_proxy; 00134 guint request_ret; 00135 00136 AUDDBG ("Registering remote D-Bus interfaces.\n"); 00137 00138 dbus_g_object_type_install_info(audacious_rc_get_type(), &dbus_glib_audacious_rc_object_info); 00139 00140 // Register DBUS path 00141 dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH, G_OBJECT(object)); 00142 00143 // Register the service name, the constants here are defined in 00144 // dbus-glib-bindings.h 00145 driver_proxy = dbus_g_proxy_new_for_name(dbus_conn, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); 00146 00147 if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE, 0, &request_ret, &error)) 00148 { 00149 g_warning("Unable to register service: %s", error->message); 00150 g_error_free(error); 00151 } 00152 00153 if (!org_freedesktop_DBus_request_name(driver_proxy, AUDACIOUS_DBUS_SERVICE_MPRIS, 0, &request_ret, &error)) 00154 { 00155 g_warning("Unable to register service: %s", error->message); 00156 g_error_free(error); 00157 } 00158 00159 g_object_unref(driver_proxy); 00160 } 00161 00162 void mpris_root_init(MprisRoot * object) 00163 { 00164 dbus_g_object_type_install_info(mpris_root_get_type(), &dbus_glib_mpris_root_object_info); 00165 00166 // Register DBUS path 00167 dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_ROOT, G_OBJECT(object)); 00168 } 00169 00170 void mpris_player_init(MprisPlayer * object) 00171 { 00172 dbus_g_object_type_install_info(mpris_player_get_type(), &dbus_glib_mpris_player_object_info); 00173 00174 // Register DBUS path 00175 dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_PLAYER, G_OBJECT(object)); 00176 00177 // Add signals 00178 DBusGProxy *proxy = object->proxy; 00179 if (proxy != NULL) 00180 { 00181 dbus_g_proxy_add_signal (proxy, "StatusChange", dbus_g_type_get_struct 00182 ("GValueArray", G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, 00183 G_TYPE_INVALID), G_TYPE_INVALID); 00184 dbus_g_proxy_add_signal (proxy, "CapsChange", G_TYPE_INT, G_TYPE_INVALID); 00185 dbus_g_proxy_add_signal(proxy, "TrackChange", DBUS_TYPE_G_STRING_VALUE_HASHTABLE, G_TYPE_INVALID); 00186 } 00187 else 00188 { 00189 /* XXX / FIXME: Why does this happen? -- ccr */ 00190 AUDDBG ("object->proxy == NULL; not adding some signals.\n"); 00191 } 00192 } 00193 00194 void mpris_tracklist_init(MprisTrackList * object) 00195 { 00196 dbus_g_object_type_install_info(mpris_tracklist_get_type(), &dbus_glib_mpris_tracklist_object_info); 00197 00198 // Register DBUS path 00199 dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_TRACKLIST, G_OBJECT(object)); 00200 00201 // Add signals 00202 DBusGProxy *proxy = object->proxy; 00203 if (proxy != NULL) 00204 { 00205 dbus_g_proxy_add_signal(proxy, "TrackListChange", G_TYPE_INT, G_TYPE_INVALID); 00206 } 00207 else 00208 { 00209 /* XXX / FIXME: Why does this happen? -- ccr */ 00210 AUDDBG ("object->proxy == NULL, not adding some signals.\n"); 00211 } 00212 00213 hook_associate("playlist update", (HookFunction) mpris_playlist_update_hook, object); 00214 } 00215 00216 void init_dbus() 00217 { 00218 GError *error = NULL; 00219 DBusConnection *local_conn; 00220 00221 main_thread = g_thread_self(); 00222 info_mutex = g_mutex_new(); 00223 info_cond = g_cond_new(); 00224 00225 AUDDBG ("Trying to initialize D-Bus.\n"); 00226 dbus_conn = dbus_g_bus_get(DBUS_BUS_SESSION, &error); 00227 if (dbus_conn == NULL) 00228 { 00229 g_warning("Unable to connect to dbus: %s", error->message); 00230 g_error_free(error); 00231 return; 00232 } 00233 00234 g_type_init(); 00235 g_object_new(audacious_rc_get_type(), NULL); 00236 g_object_new(mpris_root_get_type(), NULL); 00237 mpris = g_object_new(mpris_player_get_type(), NULL); 00238 g_object_new(mpris_tracklist_get_type(), NULL); 00239 00240 local_conn = dbus_g_connection_get_connection(dbus_conn); 00241 dbus_connection_set_exit_on_disconnect(local_conn, FALSE); 00242 } 00243 00244 static GValue *tuple_value_to_gvalue(const Tuple * tuple, const gchar * key) 00245 { 00246 GValue *val; 00247 TupleValueType type = tuple_get_value_type((Tuple *) tuple, -1, key); 00248 00249 if (type == TUPLE_STRING) 00250 { 00251 val = g_new0(GValue, 1); 00252 g_value_init(val, G_TYPE_STRING); 00253 g_value_take_string(val, g_strdup(tuple_get_string((Tuple *) tuple, -1, key))); 00254 return val; 00255 } 00256 else if (type == TUPLE_INT) 00257 { 00258 val = g_new0(GValue, 1); 00259 g_value_init(val, G_TYPE_INT); 00260 g_value_set_int(val, tuple_get_int((Tuple *) tuple, -1, key)); 00261 return val; 00262 } 00263 return NULL; 00264 } 00265 00274 static void tuple_insert_to_hash_full(GHashTable * md, const Tuple * tuple, 00275 const gchar * tuple_key, const gchar *key) 00276 { 00277 GValue *value = tuple_value_to_gvalue(tuple, tuple_key); 00278 if (value != NULL) 00279 g_hash_table_insert (md, (void *) key, value); 00280 } 00281 00282 static void tuple_insert_to_hash(GHashTable * md, const Tuple * tuple, 00283 const gchar *key) 00284 { 00285 tuple_insert_to_hash_full(md, tuple, key, key); 00286 } 00287 00288 static void remove_metadata_value(gpointer value) 00289 { 00290 g_value_unset((GValue *) value); 00291 g_free((GValue *) value); 00292 } 00293 00294 static GHashTable *make_mpris_metadata(const gchar * filename, const Tuple * tuple) 00295 { 00296 GHashTable *md = NULL; 00297 gpointer value; 00298 00299 md = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, remove_metadata_value); 00300 00301 value = g_malloc(sizeof(GValue)); 00302 memset(value, 0, sizeof(GValue)); 00303 g_value_init(value, G_TYPE_STRING); 00304 g_value_take_string(value, g_strdup(filename)); 00305 g_hash_table_insert(md, "location", value); 00306 00307 if (tuple != NULL) 00308 { 00309 tuple_insert_to_hash_full(md, tuple, "length", "mtime"); 00310 tuple_insert_to_hash(md, tuple, "title"); 00311 tuple_insert_to_hash(md, tuple, "artist"); 00312 tuple_insert_to_hash(md, tuple, "album"); 00313 tuple_insert_to_hash(md, tuple, "comment"); 00314 tuple_insert_to_hash(md, tuple, "genre"); 00315 tuple_insert_to_hash(md, tuple, "year"); 00316 tuple_insert_to_hash(md, tuple, "codec"); 00317 tuple_insert_to_hash(md, tuple, "quality"); 00318 tuple_insert_to_hash_full(md, tuple, "track-number", "tracknumber"); 00319 tuple_insert_to_hash_full(md, tuple, "bitrate", "audio-bitrate"); 00320 } 00321 00322 return md; 00323 } 00324 00325 static void real_position(gint * playlist, gint * entry) 00326 { 00327 if (*playlist == -2) 00328 *playlist = playlist_get_playing(); 00329 if (*playlist == -1) 00330 *playlist = playlist_get_active(); 00331 if (*entry == -1) 00332 *entry = playlist_get_position(*playlist); 00333 } 00334 00335 static gboolean get_status_cb(void *data) 00336 { 00337 struct StatusRequest *request = data; 00338 00339 g_mutex_lock(info_mutex); 00340 00341 memset (request, 0, sizeof (* request)); 00342 request->playing = playback_get_playing(); 00343 00344 if (request->playing) 00345 { 00346 request->paused = playback_get_paused (); 00347 request->time = playback_get_time (); 00348 request->length = playback_get_length (); 00349 playback_get_info (& request->bitrate, & request->samplerate, 00350 & request->channels); 00351 } 00352 00353 g_cond_signal(info_cond); 00354 g_mutex_unlock(info_mutex); 00355 return FALSE; 00356 } 00357 00358 static void get_status(struct StatusRequest *request) 00359 { 00360 if (g_thread_self() == main_thread) 00361 get_status_cb(request); 00362 else 00363 { 00364 g_mutex_lock(info_mutex); 00365 g_timeout_add(0, get_status_cb, request); 00366 g_cond_wait(info_cond, info_mutex); 00367 g_mutex_unlock(info_mutex); 00368 } 00369 } 00370 00371 static gboolean get_position_cb(void *data) 00372 { 00373 struct PositionRequest *request = data; 00374 00375 g_mutex_lock(info_mutex); 00376 00377 real_position(&request->playlist, &request->entry); 00378 request->entry_count = playlist_entry_count(request->playlist); 00379 request->queue_count = playlist_queue_count(request->playlist); 00380 00381 g_cond_signal(info_cond); 00382 g_mutex_unlock(info_mutex); 00383 return FALSE; 00384 } 00385 00386 static void get_position(struct PositionRequest *request) 00387 { 00388 if (g_thread_self() == main_thread) 00389 get_position_cb(request); 00390 else 00391 { 00392 g_mutex_lock(info_mutex); 00393 g_timeout_add(0, get_position_cb, request); 00394 g_cond_wait(info_cond, info_mutex); 00395 g_mutex_unlock(info_mutex); 00396 } 00397 } 00398 00399 static gboolean get_info_cb(void *data) 00400 { 00401 struct InfoRequest *request = data; 00402 const gchar *filename, *title, *pltitle; 00403 00404 g_mutex_lock(info_mutex); 00405 00406 real_position(&request->playlist, &request->entry); 00407 filename = playlist_entry_get_filename(request->playlist, request->entry); 00408 request->filename = (filename == NULL) ? NULL : g_strdup(filename); 00409 title = playlist_entry_get_title (request->playlist, request->entry, FALSE); 00410 request->title = (title == NULL) ? NULL : g_strdup(title); 00411 request->length = playlist_entry_get_length (request->playlist, 00412 request->entry, FALSE); 00413 pltitle = playlist_get_title(request->playlist); 00414 request->pltitle = (pltitle == NULL) ? NULL : g_strdup(pltitle); 00415 00416 g_cond_signal(info_cond); 00417 g_mutex_unlock(info_mutex); 00418 return FALSE; 00419 } 00420 00421 static void get_info(struct InfoRequest *request) 00422 { 00423 if (g_thread_self() == main_thread) 00424 get_info_cb(request); 00425 else 00426 { 00427 g_mutex_lock(info_mutex); 00428 g_timeout_add(0, get_info_cb, request); 00429 g_cond_wait(info_cond, info_mutex); 00430 g_mutex_unlock(info_mutex); 00431 } 00432 } 00433 00434 static gboolean get_field_cb(void *data) 00435 { 00436 struct FieldRequest *request = data; 00437 const Tuple *tuple; 00438 00439 g_mutex_lock(info_mutex); 00440 00441 real_position(&request->playlist, &request->entry); 00442 tuple = playlist_entry_get_tuple (request->playlist, request->entry, FALSE); 00443 request->value = (tuple == NULL) ? NULL : tuple_value_to_gvalue(tuple, request->field); 00444 00445 g_cond_signal(info_cond); 00446 g_mutex_unlock(info_mutex); 00447 return FALSE; 00448 } 00449 00450 static void get_field(struct FieldRequest *request) 00451 { 00452 if (g_thread_self() == main_thread) 00453 get_field_cb(request); 00454 else 00455 { 00456 g_mutex_lock(info_mutex); 00457 g_timeout_add(0, get_field_cb, request); 00458 g_cond_wait(info_cond, info_mutex); 00459 g_mutex_unlock(info_mutex); 00460 } 00461 } 00462 00463 static gboolean play_cb(void *unused) 00464 { 00465 /* Only the active playlist is visible through DBUS interface, so make sure 00466 * to play from it, not another playlist. --jlindgren */ 00467 if (playlist_get_playing () != playlist_get_active ()) 00468 playlist_set_playing (playlist_get_active ()); 00469 00470 drct_play(); 00471 return FALSE; 00472 } 00473 00474 static gboolean pause_cb(void *unused) 00475 { 00476 playback_pause(); 00477 return FALSE; 00478 } 00479 00480 static gboolean play_pause_cb(void *unused) 00481 { 00482 if (playback_get_playing()) 00483 playback_pause(); 00484 else 00485 playback_play (0, FALSE); 00486 00487 return FALSE; 00488 } 00489 00490 static gboolean seek_cb(void *data) 00491 { 00492 playback_seek (GPOINTER_TO_INT (data)); 00493 return FALSE; 00494 } 00495 00496 static gboolean stop_cb(void *unused) 00497 { 00498 playback_stop(); 00499 return FALSE; 00500 } 00501 00502 static gboolean prev_cb(void *unused) 00503 { 00504 drct_pl_prev(); 00505 return FALSE; 00506 } 00507 00508 static gboolean next_cb(void *unused) 00509 { 00510 drct_pl_next(); 00511 return FALSE; 00512 } 00513 00514 static gboolean jump_cb(void *data) 00515 { 00516 drct_pl_set_pos(GPOINTER_TO_INT(data)); 00517 return FALSE; 00518 } 00519 00520 static gboolean add_cb(void *data) 00521 { 00522 struct AddRequest *request = data; 00523 gint playlist = playlist_get_active(); 00524 00525 if (request->position < 0) 00526 request->position = playlist_entry_count (playlist); 00527 00528 drct_pl_add (request->filename, request->position); 00529 00530 if (request->play) 00531 { 00532 playlist_set_playing(playlist); 00533 playlist_set_position(playlist, request->position); 00534 playback_play (0, FALSE); 00535 } 00536 00537 g_free(request); 00538 return FALSE; 00539 } 00540 00541 static gboolean delete_cb(void *data) 00542 { 00543 drct_pl_delete(GPOINTER_TO_INT(data)); 00544 return FALSE; 00545 } 00546 00547 static gboolean clear_cb(void *unused) 00548 { 00549 drct_pl_clear(); 00550 return FALSE; 00551 } 00552 00553 static gboolean add_to_queue_cb(void *data) 00554 { 00555 drct_pq_add(GPOINTER_TO_INT(data)); 00556 return FALSE; 00557 } 00558 00559 static gboolean remove_from_queue_cb(void *data) 00560 { 00561 drct_pq_remove(GPOINTER_TO_INT(data)); 00562 return FALSE; 00563 } 00564 00565 static gboolean clear_queue_cb(void *unused) 00566 { 00567 drct_pq_clear(); 00568 return FALSE; 00569 } 00570 00571 static gboolean queue_get_entry_cb(void *data) 00572 { 00573 g_mutex_lock(info_mutex); 00574 00575 * (gint *) data = drct_pq_get_entry (* (gint *) data); 00576 00577 g_cond_signal(info_cond); 00578 g_mutex_unlock(info_mutex); 00579 return FALSE; 00580 } 00581 00582 static gint queue_get_entry(gint position) 00583 { 00584 if (g_thread_self() == main_thread) 00585 queue_get_entry_cb(&position); 00586 else 00587 { 00588 g_mutex_lock(info_mutex); 00589 g_timeout_add(0, queue_get_entry_cb, &position); 00590 g_cond_wait(info_cond, info_mutex); 00591 g_mutex_unlock(info_mutex); 00592 } 00593 00594 return position; 00595 } 00596 00597 static gboolean queue_find_entry_cb(void *data) 00598 { 00599 g_mutex_lock(info_mutex); 00600 00601 *(gint *) data = drct_pq_get_queue_position(*(gint *) data); 00602 00603 g_cond_signal(info_cond); 00604 g_mutex_unlock(info_mutex); 00605 return FALSE; 00606 } 00607 00608 static gint queue_find_entry(gint position) 00609 { 00610 if (g_thread_self() == main_thread) 00611 queue_find_entry_cb(&position); 00612 else 00613 { 00614 g_mutex_lock(info_mutex); 00615 g_timeout_add(0, queue_find_entry_cb, &position); 00616 g_cond_wait(info_cond, info_mutex); 00617 g_mutex_unlock(info_mutex); 00618 } 00619 00620 return position; 00621 } 00622 00623 gboolean add_to_new_playlist_cb(void *data) 00624 { 00625 drct_pl_open_temp (data); 00626 g_free(data); 00627 return FALSE; 00628 } 00629 00630 static gboolean get_mpris_metadata_cb(void *data) 00631 { 00632 struct MprisMetadataRequest *request = data; 00633 const gchar *filename; 00634 00635 g_mutex_lock(info_mutex); 00636 00637 real_position(&request->playlist, &request->entry); 00638 filename = playlist_entry_get_filename(request->playlist, request->entry); 00639 00640 if (filename == NULL) 00641 request->metadata = NULL; 00642 else 00643 request->metadata = make_mpris_metadata (filename, 00644 playlist_entry_get_tuple (request->playlist, request->entry, FALSE)); 00645 00646 g_cond_signal(info_cond); 00647 g_mutex_unlock(info_mutex); 00648 return FALSE; 00649 } 00650 00651 static void get_mpris_metadata(struct MprisMetadataRequest *request) 00652 { 00653 if (g_thread_self() == main_thread) 00654 get_mpris_metadata_cb(request); 00655 else 00656 { 00657 g_mutex_lock(info_mutex); 00658 g_timeout_add(0, get_mpris_metadata_cb, request); 00659 g_cond_wait(info_cond, info_mutex); 00660 g_mutex_unlock(info_mutex); 00661 } 00662 } 00663 00664 static gboolean set_shuffle_cb (void * shuffle) 00665 { 00666 cfg.shuffle = GPOINTER_TO_INT (shuffle); 00667 event_queue ("toggle shuffle", NULL); 00668 return FALSE; 00669 } 00670 00671 static gboolean set_repeat_cb (void * repeat) 00672 { 00673 cfg.repeat = GPOINTER_TO_INT (repeat); 00674 event_queue ("toggle repeat", NULL); 00675 return FALSE; 00676 } 00677 00678 /* MPRIS API */ 00679 // MPRIS / 00680 gboolean mpris_root_identity(MprisRoot * obj, gchar ** identity, GError ** error) 00681 { 00682 *identity = g_strdup_printf("Audacious %s", VERSION); 00683 return TRUE; 00684 } 00685 00686 gboolean mpris_root_quit(MprisPlayer * obj, GError ** error) 00687 { 00688 event_queue("quit", NULL); 00689 return TRUE; 00690 } 00691 00692 // MPRIS /Player 00693 00694 gboolean mpris_player_next(MprisPlayer * obj, GError * *error) 00695 { 00696 g_timeout_add(0, next_cb, NULL); 00697 return TRUE; 00698 } 00699 00700 gboolean mpris_player_prev(MprisPlayer * obj, GError * *error) 00701 { 00702 g_timeout_add(0, prev_cb, NULL); 00703 return TRUE; 00704 } 00705 00706 gboolean mpris_player_pause(MprisPlayer * obj, GError * *error) 00707 { 00708 g_timeout_add(0, pause_cb, NULL); 00709 return TRUE; 00710 } 00711 00712 gboolean mpris_player_stop(MprisPlayer * obj, GError * *error) 00713 { 00714 g_timeout_add(0, stop_cb, NULL); 00715 return TRUE; 00716 } 00717 00718 gboolean mpris_player_play(MprisPlayer * obj, GError * *error) 00719 { 00720 g_timeout_add(0, play_cb, NULL); 00721 return TRUE; 00722 } 00723 00724 gboolean mpris_player_repeat(MprisPlayer * obj, gboolean rpt, GError ** error) 00725 { 00726 fprintf (stderr, "implement me\n"); 00727 return TRUE; 00728 } 00729 00730 static void append_int_value(GValueArray * ar, gint tmp) 00731 { 00732 GValue value; 00733 memset(&value, 0, sizeof(value)); 00734 g_value_init(&value, G_TYPE_INT); 00735 g_value_set_int(&value, tmp); 00736 g_value_array_append(ar, &value); 00737 } 00738 00739 static gint get_playback_status(void) 00740 { 00741 struct StatusRequest request; 00742 get_status(&request); 00743 00744 return (!request.playing ? MPRIS_STATUS_STOP : request.paused ? MPRIS_STATUS_PAUSE : MPRIS_STATUS_PLAY); 00745 } 00746 00747 gboolean mpris_player_get_status(MprisPlayer * obj, GValueArray * *status, GError * *error) 00748 { 00749 *status = g_value_array_new(4); 00750 00751 append_int_value(*status, (gint) get_playback_status()); 00752 append_int_value(*status, (gint) cfg.shuffle); 00753 append_int_value(*status, (gint) cfg.no_playlist_advance); 00754 append_int_value(*status, (gint) cfg.repeat); 00755 return TRUE; 00756 } 00757 00758 gboolean mpris_player_get_metadata(MprisPlayer * obj, GHashTable * *metadata, GError * *error) 00759 { 00760 struct MprisMetadataRequest request = {.playlist = -1,.entry = -1 }; 00761 00762 get_mpris_metadata(&request); 00763 *metadata = request.metadata; 00764 return TRUE; 00765 } 00766 00767 gboolean mpris_player_get_caps(MprisPlayer * obj, gint * capabilities, GError ** error) 00768 { 00769 *capabilities = MPRIS_CAPS_CAN_GO_NEXT | MPRIS_CAPS_CAN_GO_PREV | MPRIS_CAPS_CAN_PAUSE | MPRIS_CAPS_CAN_PLAY | MPRIS_CAPS_CAN_SEEK | MPRIS_CAPS_CAN_PROVIDE_METADATA | MPRIS_CAPS_PROVIDES_TIMING; 00770 return TRUE; 00771 } 00772 00773 gboolean mpris_player_volume_set(MprisPlayer * obj, gint vol, GError ** error) 00774 { 00775 gint vl, vr, v; 00776 00777 // get the current volume so we can maintain the balance 00778 input_get_volume(&vl, &vr); 00779 00780 // sanity check 00781 vl = CLAMP(vl, 0, 100); 00782 vr = CLAMP(vr, 0, 100); 00783 v = CLAMP(vol, 0, 100); 00784 00785 if (vl > vr) 00786 { 00787 input_set_volume(v, (gint) rint(((gdouble) vr / vl) * v)); 00788 } 00789 else if (vl < vr) 00790 { 00791 input_set_volume((gint) rint(((gdouble) vl / vr) * v), v); 00792 } 00793 else 00794 { 00795 input_set_volume(v, v); 00796 } 00797 return TRUE; 00798 } 00799 00800 gboolean mpris_player_volume_get(MprisPlayer * obj, gint * vol, GError ** error) 00801 { 00802 gint vl, vr; 00803 input_get_volume(&vl, &vr); 00804 // vl and vr may be different depending on the balance; the true volume is 00805 // the maximum of vl or vr. 00806 *vol = MAX(vl, vr); 00807 return TRUE; 00808 } 00809 00810 gboolean mpris_player_position_set(MprisPlayer * obj, gint pos, GError * *error) 00811 { 00812 g_timeout_add(0, seek_cb, GINT_TO_POINTER(pos)); 00813 return TRUE; 00814 } 00815 00816 gboolean mpris_player_position_get(MprisPlayer * obj, gint * pos, GError * *error) 00817 { 00818 struct StatusRequest request; 00819 00820 get_status(&request); 00821 *pos = request.time; 00822 return TRUE; 00823 } 00824 00825 // MPRIS /Player signals 00826 gboolean mpris_emit_caps_change(MprisPlayer * obj) 00827 { 00828 g_signal_emit(obj, signals[CAPS_CHANGE_SIG], 0, 0); 00829 return TRUE; 00830 } 00831 00832 gboolean mpris_emit_track_change(MprisPlayer * obj) 00833 { 00834 gint playlist, entry; 00835 const gchar *filename; 00836 GHashTable *metadata; 00837 00838 playlist = playlist_get_playing(); 00839 entry = playlist_get_position(playlist); 00840 filename = playlist_entry_get_filename(playlist, entry); 00841 00842 if (filename == NULL) 00843 return FALSE; 00844 00845 metadata = make_mpris_metadata (filename, playlist_entry_get_tuple 00846 (playlist, entry, FALSE)); 00847 00848 g_signal_emit(obj, signals[TRACK_CHANGE_SIG], 0, metadata); 00849 g_hash_table_destroy(metadata); 00850 return TRUE; 00851 } 00852 00853 gboolean mpris_emit_status_change(MprisPlayer * obj, PlaybackStatus status) 00854 { 00855 GValueArray *ar = g_value_array_new(4); 00856 00857 if (status < 0) status = get_playback_status(); 00858 append_int_value(ar, (gint) status); 00859 append_int_value(ar, (gint) cfg.shuffle); 00860 append_int_value(ar, (gint) cfg.no_playlist_advance); 00861 append_int_value(ar, (gint) cfg.repeat); 00862 00863 g_signal_emit(obj, signals[STATUS_CHANGE_SIG], 0, ar); 00864 g_value_array_free(ar); 00865 return TRUE; 00866 } 00867 00868 // MPRIS /TrackList 00869 gboolean mpris_emit_tracklist_change(MprisTrackList * obj, gint playlist) 00870 { 00871 g_signal_emit(obj, tracklist_signals[TRACKLIST_CHANGE_SIG], 0, playlist_entry_count(playlist)); 00872 return TRUE; 00873 } 00874 00875 static void mpris_playlist_update_hook(gpointer unused, MprisTrackList * obj) 00876 { 00877 gint playlist = playlist_get_active(); 00878 00879 mpris_emit_tracklist_change(obj, playlist); 00880 } 00881 00882 gboolean mpris_tracklist_get_metadata(MprisTrackList * obj, gint pos, GHashTable * *metadata, GError * *error) 00883 { 00884 struct MprisMetadataRequest request = {.playlist = -1,.entry = pos }; 00885 00886 get_mpris_metadata(&request); 00887 *metadata = request.metadata; 00888 return TRUE; 00889 } 00890 00891 gboolean mpris_tracklist_get_current_track(MprisTrackList * obj, gint * pos, GError * *error) 00892 { 00893 struct PositionRequest request = {.playlist = -1,.entry = -1 }; 00894 00895 get_position(&request); 00896 *pos = request.entry; 00897 return TRUE; 00898 } 00899 00900 gboolean mpris_tracklist_get_length(MprisTrackList * obj, gint * length, GError * *error) 00901 { 00902 struct PositionRequest request = {.playlist = -1,.entry = -1 }; 00903 00904 get_position(&request); 00905 *length = request.entry_count; 00906 return TRUE; 00907 } 00908 00909 gboolean mpris_tracklist_add_track(MprisTrackList * obj, gchar * uri, gboolean play, GError * *error) 00910 { 00911 struct AddRequest *request = g_malloc(sizeof(struct AddRequest)); 00912 00913 request->position = -1; 00914 request->filename = g_strdup(uri); 00915 request->play = play; 00916 00917 g_timeout_add(0, add_cb, request); 00918 return TRUE; 00919 } 00920 00921 gboolean mpris_tracklist_del_track(MprisTrackList * obj, gint pos, GError * *error) 00922 { 00923 g_timeout_add(0, delete_cb, GINT_TO_POINTER(pos)); 00924 return TRUE; 00925 } 00926 00927 gboolean mpris_tracklist_loop (MprisTrackList * obj, gboolean loop, GError * * 00928 error) 00929 { 00930 g_timeout_add (0, set_repeat_cb, GINT_TO_POINTER (loop)); 00931 return TRUE; 00932 } 00933 00934 gboolean mpris_tracklist_random (MprisTrackList * obj, gboolean random, 00935 GError * * error) 00936 { 00937 g_timeout_add (0, set_shuffle_cb, GINT_TO_POINTER (random)); 00938 return TRUE; 00939 } 00940 00941 // Audacious General Information 00942 gboolean audacious_rc_version(RemoteObject * obj, gchar ** version, GError ** error) 00943 { 00944 *version = g_strdup(VERSION); 00945 return TRUE; 00946 } 00947 00948 gboolean audacious_rc_quit(RemoteObject * obj, GError * *error) 00949 { 00950 event_queue("quit", NULL); 00951 return TRUE; 00952 } 00953 00954 gboolean audacious_rc_eject(RemoteObject * obj, GError ** error) 00955 { 00956 interface_run_filebrowser (TRUE); 00957 return TRUE; 00958 } 00959 00960 gboolean audacious_rc_main_win_visible(RemoteObject * obj, gboolean * is_main_win, GError ** error) 00961 { 00962 *is_main_win = cfg.player_visible; 00963 return TRUE; 00964 } 00965 00966 gboolean audacious_rc_show_main_win(RemoteObject * obj, gboolean show, GError ** error) 00967 { 00968 interface_toggle_visibility (); 00969 return TRUE; 00970 } 00971 00972 gboolean audacious_rc_equalizer_visible(RemoteObject * obj, gboolean * is_eq_win, GError ** error) 00973 { 00974 *is_eq_win = cfg.equalizer_visible; 00975 return TRUE; 00976 } 00977 00978 gboolean audacious_rc_show_equalizer(RemoteObject * obj, gboolean show, GError ** error) 00979 { 00980 #if 0 00981 drct_eq_win_toggle(show); 00982 #endif 00983 return TRUE; 00984 } 00985 00986 gboolean audacious_rc_playlist_visible(RemoteObject * obj, gboolean * is_pl_win, GError ** error) 00987 { 00988 *is_pl_win = cfg.playlist_visible; 00989 return TRUE; 00990 } 00991 00992 gboolean audacious_rc_show_playlist(RemoteObject * obj, gboolean show, GError ** error) 00993 { 00994 #if 0 00995 drct_pl_win_toggle(show); 00996 #endif 00997 return TRUE; 00998 } 00999 01000 gboolean audacious_rc_get_tuple_fields(RemoteObject * obj, gchar *** fields, GError ** error) 01001 { 01002 gchar **res = g_new0(gchar *, FIELD_LAST + 1); 01003 gint i; 01004 for (i = 0; i < FIELD_LAST; i++) 01005 { 01006 res[i] = g_strdup(tuple_fields[i].name); 01007 } 01008 *fields = res; 01009 01010 return TRUE; 01011 } 01012 01013 01014 // Playback Information/Manipulation 01015 01016 gboolean audacious_rc_play(RemoteObject * obj, GError * *error) 01017 { 01018 g_timeout_add(0, play_cb, NULL); 01019 return TRUE; 01020 } 01021 01022 gboolean audacious_rc_pause(RemoteObject * obj, GError * *error) 01023 { 01024 g_timeout_add(0, pause_cb, NULL); 01025 return TRUE; 01026 } 01027 01028 gboolean audacious_rc_stop(RemoteObject * obj, GError * *error) 01029 { 01030 g_timeout_add(0, stop_cb, NULL); 01031 return TRUE; 01032 } 01033 01034 gboolean audacious_rc_playing(RemoteObject * obj, gboolean * is_playing, GError * *error) 01035 { 01036 struct StatusRequest request; 01037 01038 get_status(&request); 01039 *is_playing = request.playing; 01040 return TRUE; 01041 } 01042 01043 gboolean audacious_rc_paused(RemoteObject * obj, gboolean * is_paused, GError * *error) 01044 { 01045 struct StatusRequest request; 01046 01047 get_status(&request); 01048 *is_paused = request.paused; 01049 return TRUE; 01050 } 01051 01052 gboolean audacious_rc_stopped(RemoteObject * obj, gboolean * is_stopped, GError * *error) 01053 { 01054 struct StatusRequest request; 01055 01056 get_status(&request); 01057 *is_stopped = !request.playing; 01058 return TRUE; 01059 } 01060 01061 gboolean audacious_rc_status(RemoteObject * obj, gchar * *status, GError * *error) 01062 { 01063 struct StatusRequest request; 01064 01065 get_status(&request); 01066 *status = g_strdup(!request.playing ? "stopped" : request.paused ? "paused" : "playing"); 01067 return TRUE; 01068 } 01069 01070 gboolean audacious_rc_info(RemoteObject * obj, gint * rate, gint * freq, gint * nch, GError * *error) 01071 { 01072 struct StatusRequest request; 01073 01074 get_status(&request); 01075 *rate = request.bitrate; 01076 *freq = request.samplerate; 01077 *nch = request.channels; 01078 return TRUE; 01079 } 01080 01081 gboolean audacious_rc_time(RemoteObject * obj, gint * time, GError * *error) 01082 { 01083 struct StatusRequest request; 01084 01085 get_status(&request); 01086 *time = request.time; 01087 return TRUE; 01088 } 01089 01090 gboolean audacious_rc_seek(RemoteObject * obj, guint pos, GError * *error) 01091 { 01092 g_timeout_add(0, seek_cb, GINT_TO_POINTER(pos)); 01093 return TRUE; 01094 } 01095 01096 gboolean audacious_rc_volume(RemoteObject * obj, gint * vl, gint * vr, GError ** error) 01097 { 01098 input_get_volume(vl, vr); 01099 return TRUE; 01100 } 01101 01102 gboolean audacious_rc_set_volume(RemoteObject * obj, gint vl, gint vr, GError ** error) 01103 { 01104 if (vl > 100) 01105 vl = 100; 01106 if (vr > 100) 01107 vr = 100; 01108 input_set_volume(vl, vr); 01109 return TRUE; 01110 } 01111 01112 gboolean audacious_rc_balance(RemoteObject * obj, gint * balance, GError ** error) 01113 { 01114 gint vl, vr; 01115 input_get_volume(&vl, &vr); 01116 if (vl < 0 || vr < 0) 01117 *balance = 0; 01118 else if (vl > vr) 01119 *balance = -100 + ((vr * 100) / vl); 01120 else if (vr > vl) 01121 *balance = 100 - ((vl * 100) / vr); 01122 else 01123 *balance = 0; 01124 return TRUE; 01125 } 01126 01127 // Playlist Information/Manipulation 01128 01129 gboolean audacious_rc_position(RemoteObject * obj, gint * pos, GError * *error) 01130 { 01131 struct PositionRequest request = {.playlist = -1,.entry = -1 }; 01132 01133 get_position(&request); 01134 *pos = request.entry; 01135 return TRUE; 01136 } 01137 01138 gboolean audacious_rc_advance(RemoteObject * obj, GError * *error) 01139 { 01140 g_timeout_add(0, next_cb, NULL); 01141 return TRUE; 01142 } 01143 01144 gboolean audacious_rc_reverse(RemoteObject * obj, GError * *error) 01145 { 01146 g_timeout_add(0, prev_cb, NULL); 01147 return TRUE; 01148 } 01149 01150 gboolean audacious_rc_length(RemoteObject * obj, gint * length, GError * *error) 01151 { 01152 struct PositionRequest request = {.playlist = -1,.entry = -1 }; 01153 01154 get_position(&request); 01155 *length = request.entry_count; 01156 return TRUE; 01157 } 01158 01159 gboolean audacious_rc_song_title(RemoteObject * obj, guint pos, gchar * *title, GError * *error) 01160 { 01161 struct InfoRequest request = {.playlist = -1,.entry = pos }; 01162 01163 get_info(&request); 01164 g_free(request.filename); 01165 g_free(request.pltitle); 01166 *title = request.title; 01167 return TRUE; 01168 } 01169 01170 gboolean audacious_rc_song_filename(RemoteObject * obj, guint pos, gchar * *filename, GError * *error) 01171 { 01172 struct InfoRequest request = {.playlist = -1,.entry = pos }; 01173 01174 get_info(&request); 01175 *filename = request.filename; 01176 g_free(request.title); 01177 g_free(request.pltitle); 01178 return TRUE; 01179 } 01180 01181 gboolean audacious_rc_song_length(RemoteObject * obj, guint pos, gint * length, GError * *error) 01182 { 01183 audacious_rc_song_frames(obj, pos, length, error); 01184 *length /= 1000; 01185 return TRUE; 01186 } 01187 01188 gboolean audacious_rc_song_frames(RemoteObject * obj, guint pos, gint * length, GError * *error) 01189 { 01190 struct InfoRequest request = {.playlist = -1,.entry = pos }; 01191 01192 get_info(&request); 01193 g_free(request.filename); 01194 g_free(request.title); 01195 g_free(request.pltitle); 01196 *length = request.length; 01197 return TRUE; 01198 } 01199 01200 gboolean audacious_rc_song_tuple(RemoteObject * obj, guint pos, gchar * field, GValue * value, GError * *error) 01201 { 01202 struct FieldRequest request = {.playlist = -1,.entry = pos,.field = field }; 01203 01204 get_field(&request); 01205 01206 if (request.value == NULL) 01207 return FALSE; 01208 01209 memset(value, 0, sizeof(GValue)); 01210 g_value_init(value, G_VALUE_TYPE(request.value)); 01211 g_value_copy(request.value, value); 01212 g_value_unset(request.value); 01213 g_free(request.value); 01214 return TRUE; 01215 } 01216 01217 gboolean audacious_rc_jump(RemoteObject * obj, guint pos, GError * *error) 01218 { 01219 g_timeout_add(0, jump_cb, GINT_TO_POINTER(pos)); 01220 return TRUE; 01221 } 01222 01223 gboolean audacious_rc_add(RemoteObject * obj, gchar * file, GError * *error) 01224 { 01225 return audacious_rc_playlist_ins_url_string(obj, file, -1, error); 01226 } 01227 01228 gboolean audacious_rc_add_url(RemoteObject * obj, gchar * file, GError * *error) 01229 { 01230 return audacious_rc_playlist_ins_url_string(obj, file, -1, error); 01231 } 01232 01233 static GList * string_array_to_list (gchar * * strings) 01234 { 01235 GList * list = NULL; 01236 01237 while (* strings != NULL) 01238 list = g_list_prepend (list, * strings ++); 01239 01240 return g_list_reverse (list); 01241 } 01242 01243 gboolean audacious_rc_add_list (RemoteObject * obj, gchar * * filenames, 01244 GError * * error) 01245 { 01246 GList * list = string_array_to_list (filenames); 01247 01248 drct_pl_add_list (list, -1); 01249 g_list_free (list); 01250 return TRUE; 01251 } 01252 01253 gboolean audacious_rc_open_list (RemoteObject * obj, gchar * * filenames, 01254 GError * * error) 01255 { 01256 GList * list = string_array_to_list (filenames); 01257 01258 drct_pl_open_list (list); 01259 g_list_free (list); 01260 return TRUE; 01261 } 01262 01263 gboolean audacious_rc_open_list_to_temp (RemoteObject * obj, gchar * * 01264 filenames, GError * * error) 01265 { 01266 GList * list = string_array_to_list (filenames); 01267 01268 drct_pl_open_temp_list (list); 01269 g_list_free (list); 01270 return TRUE; 01271 } 01272 01273 gboolean audacious_rc_delete(RemoteObject * obj, guint pos, GError * *error) 01274 { 01275 g_timeout_add(0, delete_cb, GINT_TO_POINTER(pos)); 01276 return TRUE; 01277 } 01278 01279 gboolean audacious_rc_clear(RemoteObject * obj, GError * *error) 01280 { 01281 g_timeout_add(0, clear_cb, NULL); 01282 return TRUE; 01283 } 01284 01285 gboolean audacious_rc_auto_advance(RemoteObject * obj, gboolean * is_advance, GError ** error) 01286 { 01287 *is_advance = !cfg.no_playlist_advance; 01288 return TRUE; 01289 } 01290 01291 gboolean audacious_rc_toggle_auto_advance(RemoteObject * obj, GError ** error) 01292 { 01293 cfg.no_playlist_advance = !cfg.no_playlist_advance; 01294 return TRUE; 01295 } 01296 01297 gboolean audacious_rc_repeat(RemoteObject * obj, gboolean * is_repeating, GError ** error) 01298 { 01299 *is_repeating = cfg.repeat; 01300 return TRUE; 01301 } 01302 01303 gboolean audacious_rc_toggle_repeat (RemoteObject * obj, GError * * error) 01304 { 01305 g_timeout_add (0, set_repeat_cb, GINT_TO_POINTER (! cfg.repeat)); 01306 return TRUE; 01307 } 01308 01309 gboolean audacious_rc_shuffle(RemoteObject * obj, gboolean * is_shuffling, GError ** error) 01310 { 01311 *is_shuffling = cfg.shuffle; 01312 return TRUE; 01313 } 01314 01315 gboolean audacious_rc_toggle_shuffle (RemoteObject * obj, GError * * error) 01316 { 01317 g_timeout_add (0, set_shuffle_cb, GINT_TO_POINTER (! cfg.shuffle)); 01318 return TRUE; 01319 } 01320 01321 /* New on Oct 5 */ 01322 gboolean audacious_rc_show_prefs_box(RemoteObject * obj, gboolean show, GError ** error) 01323 { 01324 event_queue("prefswin show", GINT_TO_POINTER(show)); 01325 return TRUE; 01326 } 01327 01328 gboolean audacious_rc_show_about_box(RemoteObject * obj, gboolean show, GError ** error) 01329 { 01330 event_queue("aboutwin show", GINT_TO_POINTER(show)); 01331 return TRUE; 01332 } 01333 01334 gboolean audacious_rc_show_jtf_box(RemoteObject * obj, gboolean show, GError ** error) 01335 { 01336 if (show) 01337 event_queue("interface show jump to track", NULL); 01338 else 01339 event_queue("interface hide jump to track", NULL); 01340 return TRUE; 01341 } 01342 01343 gboolean audacious_rc_show_filebrowser(RemoteObject * obj, gboolean show, GError ** error) 01344 { 01345 if (show) 01346 event_queue("filebrowser show", GINT_TO_POINTER(FALSE)); 01347 else 01348 event_queue("filebrowser hide", NULL); 01349 return TRUE; 01350 } 01351 01352 gboolean audacious_rc_play_pause(RemoteObject * obj, GError * *error) 01353 { 01354 g_timeout_add(0, play_pause_cb, NULL); 01355 return TRUE; 01356 } 01357 01358 gboolean audacious_rc_activate(RemoteObject * obj, GError ** error) 01359 { 01360 fprintf (stderr, "implement me\n"); 01361 return TRUE; 01362 } 01363 01364 gboolean audacious_rc_get_info(RemoteObject * obj, gint * rate, gint * freq, gint * nch, GError * *error) 01365 { 01366 struct StatusRequest request; 01367 01368 get_status(&request); 01369 *rate = request.bitrate; 01370 *freq = request.samplerate; 01371 *nch = request.channels; 01372 return TRUE; 01373 } 01374 01375 gboolean audacious_rc_toggle_aot(RemoteObject * obj, gboolean ontop, GError ** error) 01376 { 01377 hook_call("mainwin set always on top", &ontop); 01378 return TRUE; 01379 } 01380 01381 gboolean audacious_rc_playqueue_add(RemoteObject * obj, gint pos, GError * *error) 01382 { 01383 g_timeout_add(0, add_to_queue_cb, GINT_TO_POINTER(pos)); 01384 return TRUE; 01385 } 01386 01387 gboolean audacious_rc_playqueue_remove(RemoteObject * obj, gint pos, GError * *error) 01388 { 01389 g_timeout_add(0, remove_from_queue_cb, GINT_TO_POINTER(pos)); 01390 return TRUE; 01391 } 01392 01393 gboolean audacious_rc_playqueue_clear(RemoteObject * obj, GError * *error) 01394 { 01395 g_timeout_add(0, clear_queue_cb, NULL); 01396 return TRUE; 01397 } 01398 01399 gboolean audacious_rc_get_playqueue_length(RemoteObject * obj, gint * length, GError * *error) 01400 { 01401 struct PositionRequest request = {.playlist = -1,.entry = -1 }; 01402 01403 get_position(&request); 01404 *length = request.queue_count; 01405 return TRUE; 01406 } 01407 01408 gboolean audacious_rc_queue_get_list_pos(RemoteObject * obj, gint qpos, gint * pos, GError * *error) 01409 { 01410 *pos = queue_get_entry(qpos); 01411 return TRUE; 01412 } 01413 01414 gboolean audacious_rc_queue_get_queue_pos(RemoteObject * obj, gint pos, gint * qpos, GError * *error) 01415 { 01416 *qpos = queue_find_entry(pos); 01417 return TRUE; 01418 } 01419 01420 gboolean audacious_rc_playqueue_is_queued(RemoteObject * obj, gint pos, gboolean * is_queued, GError * *error) 01421 { 01422 *is_queued = (queue_find_entry(pos) != -1); 01423 return TRUE; 01424 } 01425 01426 gboolean audacious_rc_playlist_ins_url_string(RemoteObject * obj, gchar * url, gint pos, GError * *error) 01427 { 01428 struct AddRequest *request = g_malloc(sizeof(struct AddRequest)); 01429 01430 request->position = pos; 01431 request->filename = g_strdup(url); 01432 request->play = FALSE; 01433 01434 g_timeout_add(0, add_cb, request); 01435 return TRUE; 01436 } 01437 01438 gboolean audacious_rc_playlist_add(RemoteObject * obj, void *list, GError * *error) 01439 { 01440 return audacious_rc_playlist_ins_url_string(obj, list, -1, error); 01441 } 01442 01443 gboolean audacious_rc_playlist_enqueue_to_temp(RemoteObject * obj, gchar * url, GError * *error) 01444 { 01445 g_timeout_add(0, add_to_new_playlist_cb, g_strdup(url)); 01446 return TRUE; 01447 } 01448 01449 /* New on Nov 7: Equalizer */ 01450 gboolean audacious_rc_get_eq(RemoteObject * obj, gdouble * preamp, GArray ** bands, GError ** error) 01451 { 01452 int i; 01453 01454 * preamp = cfg.equalizer_preamp; 01455 *bands = g_array_sized_new(FALSE, FALSE, sizeof(gdouble), AUD_EQUALIZER_NBANDS); 01456 01457 for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) 01458 g_array_append_val (* bands, cfg.equalizer_bands[i]); 01459 01460 return TRUE; 01461 } 01462 01463 gboolean audacious_rc_get_eq_preamp(RemoteObject * obj, gdouble * preamp, GError ** error) 01464 { 01465 * preamp = cfg.equalizer_preamp; 01466 return TRUE; 01467 } 01468 01469 gboolean audacious_rc_get_eq_band(RemoteObject * obj, gint band, gdouble * value, GError ** error) 01470 { 01471 * value = cfg.equalizer_bands[band]; 01472 return TRUE; 01473 } 01474 01475 gboolean audacious_rc_set_eq(RemoteObject * obj, gdouble preamp, GArray * bands, GError ** error) 01476 { 01477 int i; 01478 01479 cfg.equalizer_preamp = preamp; 01480 01481 for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) 01482 cfg.equalizer_bands[i] = g_array_index (bands, gdouble, i); 01483 01484 hook_call ("equalizer changed", NULL); 01485 return TRUE; 01486 } 01487 01488 gboolean audacious_rc_set_eq_preamp(RemoteObject * obj, gdouble preamp, GError ** error) 01489 { 01490 cfg.equalizer_preamp = preamp; 01491 hook_call ("equalizer changed", NULL); 01492 return TRUE; 01493 } 01494 01495 gboolean audacious_rc_set_eq_band(RemoteObject * obj, gint band, gdouble value, GError ** error) 01496 { 01497 cfg.equalizer_bands[band] = value; 01498 hook_call ("equalizer changed", NULL); 01499 return TRUE; 01500 } 01501 01502 gboolean audacious_rc_equalizer_activate(RemoteObject * obj, gboolean active, GError ** error) 01503 { 01504 cfg.equalizer_active = active; 01505 hook_call ("equalizer changed", NULL); 01506 return TRUE; 01507 } 01508 01509 gboolean audacious_rc_get_active_playlist_name(RemoteObject * obj, gchar * *title, GError * *error) 01510 { 01511 struct InfoRequest request = {.playlist = -2 }; 01512 01513 get_info(&request); 01514 g_free(request.title); 01515 g_free(request.filename); 01516 *title = request.pltitle; 01517 return TRUE; 01518 } 01519 01520 DBusGProxy *audacious_get_dbus_proxy(void) 01521 { 01522 DBusGConnection *connection = NULL; 01523 GError *error = NULL; 01524 connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error); 01525 g_clear_error(&error); 01526 return dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE, AUDACIOUS_DBUS_PATH, AUDACIOUS_DBUS_INTERFACE); 01527 }