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
// Read 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_start(MediaPlayerRec *player) {
36
// Called when Banshee player starts a new track
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_PLAYING;
46
dbus_player_debug_print(player);
49
dbus_player_process_data(player);
52
void banshee_player_track_stop(MediaPlayerRec *player) {
53
// Called when Banshee player ends a track
55
// Re-read all player data
56
banshee_get_info(player);
58
// Set track changed signal
59
TrackInfo *tr = &player->track;
60
tr->status = PLAYER_STATUS_STOPPED;
63
dbus_player_debug_print(player);
66
dbus_player_process_data(player);
70
void banshee_player_track_changed(MediaPlayerRec *player) {
71
// Called when track changes
73
// Re-read all player data
74
banshee_get_info(player);
76
// Set track changed signal
77
TrackInfo *tr = &player->track;
78
tr->status = PLAYER_STATUS_TRACK_CHANGE;
81
dbus_player_debug_print(player);
84
dbus_player_process_data(player);
88
void banshee_player_status_changed(MediaPlayerRec *player) {
89
// Called when player's status or track changes
91
// Re-read all player data
92
banshee_get_info(player);
95
// dbus_player_debug_print(player);
98
dbus_player_process_data(player);
101
void banshee_get_app_name(MediaPlayerRec *player) {
102
// Name of the Banshee media player.
103
player->app_name = g_strdup(_("Banshee Media Player"));
106
void banshee_state_signal_cb(DBusGProxy *player_proxy, gchar *state, MediaPlayerRec *player) {
107
// State signal from Banshee
110
// "idle" (quit player)
116
// LOG_PLAYER("banshee_state_signal_cb: %s (%s) got state:<%s>\n", player->app_name, player->service_name, state);
118
if ((!g_strcmp0(state, "idle")) || // Quit player
119
(!g_strcmp0(state, "playing")) || // Play
120
(!g_strcmp0(state, "paused"))) {
122
// We do not utilize these state-events at the moment. See the banshee_event_signal_cb() function below.
124
// Re-read all data and inform GUI
125
// banshee_player_status_changed(player);
129
void banshee_event_signal_cb(DBusGProxy *player_proxy, gchar *event, gchar *message, gdouble buffering_percentage, MediaPlayerRec *player) {
130
// Event signal from Banshee
136
// "requestnexttrack"
140
LOG_PLAYER("banshee_event_signal_cb: %s (%s) got event:<%s>\n", player->app_name, player->service_name, event);
142
if (!g_strcmp0(event, "volume")) {
144
} else if (!g_strcmp0(event, "seek")) {
146
} else if (!g_strcmp0(event, "requestnexttrack")) {
148
} else if (!g_strcmp0(event, "statechange")) {
150
// Re-read all data and inform the recorder
151
banshee_player_status_changed(player);
153
} else if (!g_strcmp0(event, "startofstream")) {
155
// Stop and start of a new stream/track. Inform the recorder
156
banshee_player_track_stop(player);
157
banshee_player_track_start(player);
159
} else if (!g_strcmp0(event, "endofstream")) {
161
// End of track/stream. Inform the recorder
162
banshee_player_track_stop(player);
166
gboolean banshee_check_proxy(MediaPlayerRec *player) {
169
if (!player) return FALSE;
171
if (!player->proxy) {
172
DBusGConnection *dbus_conn = dbus_player_connect_to_dbus();
174
player->proxy = dbus_g_proxy_new_for_name(dbus_conn,
175
player->service_name,
176
"/org/bansheeproject/Banshee/PlayerEngine",
177
"org.bansheeproject.Banshee.PlayerEngine");
180
if (!player->proxy) {
181
LOG_ERROR("banshee_check_proxy: Cannot create DBus proxy for Banshee.\n");
184
return (player->proxy != NULL);
187
void banshee_set_signals(gpointer player_rec, gboolean connect) {
188
// Connect/disconnect signals
190
MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
193
if (!player->proxy) {
195
if (!banshee_check_proxy(player)) return;
197
// Register arguments.
198
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);
200
dbus_g_proxy_add_signal(player->proxy, "StateChanged", G_TYPE_STRING, G_TYPE_INVALID);
201
dbus_g_proxy_add_signal(player->proxy, "EventChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_INVALID);
204
if (!banshee_check_proxy(player)) return;
208
dbus_g_proxy_connect_signal(player->proxy, "StateChanged", G_CALLBACK(banshee_state_signal_cb), (gpointer)player, NULL);
209
dbus_g_proxy_connect_signal(player->proxy, "EventChanged", G_CALLBACK(banshee_event_signal_cb), (gpointer)player, NULL);
211
// Disconnect signals
212
dbus_g_proxy_disconnect_signal(player->proxy, "StateChanged", G_CALLBACK(banshee_state_signal_cb), (gpointer)player);
213
dbus_g_proxy_disconnect_signal(player->proxy, "EventChanged", G_CALLBACK(banshee_event_signal_cb), (gpointer)player);
217
void banshee_hash_str(GHashTable *table, gchar *key, gchar *dest) {
220
GValue* value = (GValue*) g_hash_table_lookup(table, key);
221
if (G_VALUE_HOLDS_STRING(value)) {
222
str_copy(dest, (gchar*)g_value_get_string(value), MPRIS_STRLEN-1);
226
gboolean banshee_dbus_string(DBusGProxy *proxy, gchar *method, gchar* dest) {
231
if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
236
LOG_ERROR("banshee_dbus_string: Failed to make DBus call %s: %s", method, error ? error->message : "");
247
str_copy(dest, str, MPRIS_STRLEN-1);
248
dest[MPRIS_STRLEN-1] = '\0';
253
gint banshee_dbus_int(DBusGProxy *proxy, const char *method) {
255
GError *error = NULL;
256
if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
261
LOG_ERROR("banshee_dbus_int: Failed to make DBus call %s: %s", method, error ? error->message : "");
272
guint banshee_dbus_uint(DBusGProxy *proxy, const char *method) {
274
GError *error = NULL;
275
if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
280
LOG_ERROR("banshee_dbus_uint: Failed to make DBus call %s: %s", method, error ? error->message : "");
291
void banshee_get_info(gpointer player_rec) {
292
MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
293
TrackInfo *tr = &player->track;
295
// Is this player running/active?
296
player->active = mpris_service_is_running_by_name(player->service_name);
297
if (!player->active) {
298
tr->status = PLAYER_STATUS_CLOSED;
303
if (!banshee_check_proxy(player)) return;
305
char str[MPRIS_STRLEN];
307
if (!banshee_dbus_string(player->proxy, "GetCurrentState", str)) {
308
// Application has exited/shutdown
309
player->active = FALSE;
310
tr->status = PLAYER_STATUS_STOPPED;
314
if (!g_strcmp0(str, "idle")) {
315
tr->status = PLAYER_STATUS_STOPPED;
318
} else if (!g_strcmp0(str, "playing")) {
319
tr->status = PLAYER_STATUS_PLAYING;
321
tr->status = PLAYER_STATUS_PAUSED;
324
GError *error = NULL;
325
GHashTable* table = NULL;
327
if (!dbus_g_proxy_call_with_timeout(player->proxy, "GetCurrentTrack", DBUS_MPRIS_TIMEOUT, &error, G_TYPE_INVALID,
328
dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &table,G_TYPE_INVALID)) {
330
LOG_ERROR("banshee_get_info: Failed to make DBus call: %s", error ? error->message : "");
338
banshee_hash_str(table, "album", tr->album);
339
banshee_hash_str(table, "artist", tr->artist);
340
banshee_hash_str(table, "name", tr->track);
342
g_hash_table_destroy(table);
344
tr->total_secs = banshee_dbus_uint(player->proxy, "GetLength") / 1000;
345
tr->current_secs = banshee_dbus_uint(player->proxy, "GetPosition") / 1000;
351
void banshee_start_app(gpointer player_rec) {
354
MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
357
if (!banshee_check_proxy(player)) return;
359
dbus_g_proxy_call_no_reply(player->proxy, "Start", G_TYPE_INVALID);
363
VOID:STRING,STRING,DOUBLE (marshal.list:1)
364
Ref: http://web.archive.org/web/20080501043040/http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices
367
$ echo "VOID:STRING,STRING,DOUBLE" > marshal.list
369
$ glib-genmarshal --prefix=marshal marshal.list --header > sample1.h
370
$ glib-genmarshal --prefix=marshal marshal.list --body > sample1.c
374
void marshal_VOID__STRING_STRING_DOUBLE (GClosure *closure,
375
GValue *return_value G_GNUC_UNUSED,
376
guint n_param_values,
377
const GValue *param_values,
378
gpointer invocation_hint G_GNUC_UNUSED,
379
gpointer marshal_data) {
380
typedef void (*GMarshalFunc_VOID__STRING_STRING_DOUBLE) (gpointer data1,
385
register GMarshalFunc_VOID__STRING_STRING_DOUBLE callback;
386
register GCClosure *cc = (GCClosure*) closure;
387
register gpointer data1, data2;
389
g_return_if_fail (n_param_values == 4);
391
if (G_CCLOSURE_SWAP_DATA (closure)) {
392
data1 = closure->data;
393
data2 = g_value_peek_pointer (param_values + 0);
395
data1 = g_value_peek_pointer (param_values + 0);
396
data2 = closure->data;
398
callback = (GMarshalFunc_VOID__STRING_STRING_DOUBLE) (marshal_data ? marshal_data : cc->callback);
401
g_marshal_value_peek_string (param_values + 1),
402
g_marshal_value_peek_string (param_values + 2),
403
g_marshal_value_peek_double (param_values + 3),