2
* Copyright (c) Linux community.
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Library General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Library General Public License for more details.
14
* You should have received a copy of the GNU Library General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
19
#include "dbus_player.h"
20
#include "dbus_mpris.h"
21
#include "dbus_banshee.h"
22
#include "dbus_marshal.h"
28
// http://code.google.com/p/pidgin-musictracker/source/browse/trunk/src/banshee.c?r=446
30
// See also dev-info/*banshee_readme.txt
32
void marshal_VOID__STRING_STRING_DOUBLE (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values,
33
const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED,gpointer marshal_data);
35
void banshee_player_track_changed(MediaPlayerRec *player) {
36
// Called when track changes
38
// Re-read all player data
39
banshee_get_info(player);
41
// Set track changed signal
42
TrackInfo *tr = &player->track;
43
tr->status = PLAYER_STATUS_TRACK_CHANGE;
46
// dbus_player_debug_print(player);
49
dbus_player_process_data(player);
52
void banshee_player_status_changed(MediaPlayerRec *player) {
53
// Called when player's status or track changes
55
// Re-read all player data
56
banshee_get_info(player);
59
// dbus_player_debug_print(player);
62
dbus_player_process_data(player);
65
void banshee_get_app_name(MediaPlayerRec *player) {
66
player->app_name = g_strdup(_("Banshee Media Player"));
69
void banshee_state_signal_cb(DBusGProxy *player_proxy, gchar *state, MediaPlayerRec *player) {
70
// State signal from Banshee
73
// "idle" (quit player)
79
if ((!g_strcmp0(state, "idle")) || // Quit player
80
(!g_strcmp0(state, "playing")) || // Play
81
(!g_strcmp0(state, "paused"))) {
83
// We do not utilize these state-events at the moment. See the banshee_event_signal_cb() function below.
85
// Re-read all data and inform GUI
86
// banshee_player_status_changed(player);
90
void banshee_event_signal_cb(DBusGProxy *player_proxy, gchar *event, gchar *message, gdouble buffering_percentage, MediaPlayerRec *player) {
91
// Event signal from Banshee
101
LOG_PLAYER("banshee_event_signal_cb: %s (%s) got event:<%s>\n", player->app_name, player->service_name, event);
103
if (!g_strcmp0(event, "volume")) {
106
else if (!g_strcmp0(event, "seek")) {
109
else if (!g_strcmp0(event, "requestnexttrack")) {
112
else if (!g_strcmp0(event, "statechange")) {
114
// Re-read all data and inform the recorder
115
banshee_player_status_changed(player);
117
else if (!g_strcmp0(event, "startofstream")) {
119
// Re-read all data and inform the recorder
120
banshee_player_status_changed(player);
123
else if (!g_strcmp0(event, "endofstream")) {
125
// Track changed. Inform the recorder
126
banshee_player_track_changed(player);
130
gboolean banshee_check_proxy(MediaPlayerRec *player) {
133
if (!player) return FALSE;
135
if (!player->proxy) {
136
DBusGConnection *dbus_conn = dbus_player_connect_to_dbus();
138
player->proxy = dbus_g_proxy_new_for_name(dbus_conn,
139
player->service_name,
140
"/org/bansheeproject/Banshee/PlayerEngine",
141
"org.bansheeproject.Banshee.PlayerEngine");
144
if (!player->proxy) {
145
LOG_ERROR("banshee_check_proxy: Cannot create DBus proxy for Banshee.\n");
148
return (player->proxy != NULL);
151
void banshee_set_signals(gpointer player_rec, gboolean connect) {
152
// Connect/disconnect signals
154
MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
157
if (!player->proxy) {
159
if (!banshee_check_proxy(player)) return;
161
// Register arguments.
162
dbus_g_object_register_marshaller(marshal_VOID__STRING_STRING_DOUBLE, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_INVALID);
164
dbus_g_proxy_add_signal(player->proxy, "StateChanged", G_TYPE_STRING, G_TYPE_INVALID);
165
dbus_g_proxy_add_signal(player->proxy, "EventChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_INVALID);
168
if (!banshee_check_proxy(player)) return;
172
dbus_g_proxy_connect_signal(player->proxy, "StateChanged", G_CALLBACK(banshee_state_signal_cb), (gpointer)player, NULL);
173
dbus_g_proxy_connect_signal(player->proxy, "EventChanged", G_CALLBACK(banshee_event_signal_cb), (gpointer)player, NULL);
175
// Disconnect signals
176
dbus_g_proxy_disconnect_signal(player->proxy, "StateChanged", G_CALLBACK(banshee_state_signal_cb), (gpointer)player);
177
dbus_g_proxy_disconnect_signal(player->proxy, "EventChanged", G_CALLBACK(banshee_event_signal_cb), (gpointer)player);
181
void banshee_hash_str(GHashTable *table, gchar *key, gchar *dest) {
184
GValue* value = (GValue*) g_hash_table_lookup(table, key);
185
if (G_VALUE_HOLDS_STRING(value)) {
186
str_copy(dest, (gchar*)g_value_get_string(value), MPRIS_STRLEN-1);
190
gboolean banshee_dbus_string(DBusGProxy *proxy, gchar *method, gchar* dest) {
195
if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
200
LOG_ERROR("banshee_dbus_string: Failed to make DBus call %s: %s", method, error ? error->message : "");
202
g_free(str); str = NULL;
210
str_copy(dest, str, MPRIS_STRLEN-1);
211
dest[MPRIS_STRLEN-1] = '\0';
216
gint banshee_dbus_int(DBusGProxy *proxy, const char *method) {
218
GError *error = NULL;
219
if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
224
LOG_ERROR("banshee_dbus_int: Failed to make DBus call %s: %s", method, error ? error->message : "");
235
guint banshee_dbus_uint(DBusGProxy *proxy, const char *method) {
237
GError *error = NULL;
238
if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
243
LOG_ERROR("banshee_dbus_uint: Failed to make DBus call %s: %s", method, error ? error->message : "");
254
void banshee_get_info(gpointer player_rec) {
255
MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
256
TrackInfo *tr = &player->track;
258
// Is this player running/active?
259
player->active = mpris_service_is_running_by_name(player->service_name);
260
if (!player->active) {
261
tr->status = PLAYER_STATUS_CLOSED;
266
if (!banshee_check_proxy(player)) return;
268
char str[MPRIS_STRLEN];
270
if (!banshee_dbus_string(player->proxy, "GetCurrentState", str)) {
271
// Application has exited/shutdown
272
player->active = FALSE;
273
tr->status = PLAYER_STATUS_STOPPED;
277
if (!g_strcmp0(str, "idle")) {
278
tr->status = PLAYER_STATUS_STOPPED;
281
} else if (!g_strcmp0(str, "playing")) {
282
tr->status = PLAYER_STATUS_PLAYING;
285
tr->status = PLAYER_STATUS_PAUSED;
288
GError *error = NULL;
289
GHashTable* table = NULL;
291
if (!dbus_g_proxy_call_with_timeout(player->proxy, "GetCurrentTrack", DBUS_MPRIS_TIMEOUT, &error, G_TYPE_INVALID,
292
dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &table,G_TYPE_INVALID)) {
294
LOG_ERROR("banshee_get_info: Failed to make DBus call: %s", error ? error->message : "");
302
banshee_hash_str(table, "album", tr->album);
303
banshee_hash_str(table, "artist", tr->artist);
304
banshee_hash_str(table, "name", tr->track);
306
g_hash_table_destroy(table);
308
tr->total_secs = banshee_dbus_uint(player->proxy, "GetLength") / 1000;
309
tr->current_secs = banshee_dbus_uint(player->proxy, "GetPosition") / 1000;
315
void banshee_start_app(gpointer player_rec) {
318
MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
321
if (!banshee_check_proxy(player)) return;
323
dbus_g_proxy_call_no_reply(player->proxy, "Start", G_TYPE_INVALID);
327
VOID:STRING,STRING,DOUBLE (marshal.list:1)
328
Ref: http://web.archive.org/web/20080501043040/http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices
331
$ echo "VOID:STRING,STRING,DOUBLE" > marshal.list
333
$ glib-genmarshal --prefix=marshal marshal.list --header > sample1.h
334
$ glib-genmarshal --prefix=marshal marshal.list --body > sample1.c
338
void marshal_VOID__STRING_STRING_DOUBLE (GClosure *closure,
339
GValue *return_value G_GNUC_UNUSED,
340
guint n_param_values,
341
const GValue *param_values,
342
gpointer invocation_hint G_GNUC_UNUSED,
343
gpointer marshal_data)
345
typedef void (*GMarshalFunc_VOID__STRING_STRING_DOUBLE) (gpointer data1,
350
register GMarshalFunc_VOID__STRING_STRING_DOUBLE callback;
351
register GCClosure *cc = (GCClosure*) closure;
352
register gpointer data1, data2;
354
g_return_if_fail (n_param_values == 4);
356
if (G_CCLOSURE_SWAP_DATA (closure)) {
357
data1 = closure->data;
358
data2 = g_value_peek_pointer (param_values + 0);
361
data1 = g_value_peek_pointer (param_values + 0);
362
data2 = closure->data;
364
callback = (GMarshalFunc_VOID__STRING_STRING_DOUBLE) (marshal_data ? marshal_data : cc->callback);
367
g_marshal_value_peek_string (param_values + 1),
368
g_marshal_value_peek_string (param_values + 2),
369
g_marshal_value_peek_double (param_values + 3),