~audio-recorder/audio-recorder/trunk

« back to all changes in this revision

Viewing changes to src/dbus_banshee.c

  • Committer: Osmo Antero Maatta
  • Date: 2011-01-17 08:09:50 UTC
  • Revision ID: osmoma@gmail.com-20110117080950-4cbm2fnnsr0332jw
InitialĀ importĀ 17.jan.2011

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (c) Linux community.
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 */
 
19
#include "dbus_player.h"
 
20
#include "dbus_mpris.h"
 
21
#include "dbus_banshee.h"
 
22
#include "dbus_marshal.h"
 
23
#include "log.h"
 
24
#include "support.h"
 
25
#include "utility.h"
 
26
 
 
27
// Thanks to:
 
28
// http://code.google.com/p/pidgin-musictracker/source/browse/trunk/src/banshee.c?r=446
 
29
//
 
30
// See also dev-info/*banshee_readme.txt
 
31
 
 
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);
 
34
 
 
35
void banshee_player_track_changed(MediaPlayerRec *player) {
 
36
    // Called when track changes
 
37
 
 
38
    // Re-read all player data
 
39
    banshee_get_info(player);
 
40
 
 
41
    // Set track changed signal
 
42
    TrackInfo *tr = &player->track;
 
43
    tr->status = PLAYER_STATUS_TRACK_CHANGE;
 
44
 
 
45
    // Print debug info
 
46
    // dbus_player_debug_print(player);
 
47
 
 
48
    // Process data 
 
49
    dbus_player_process_data(player);
 
50
}
 
51
 
 
52
void banshee_player_status_changed(MediaPlayerRec *player) {
 
53
    // Called when player's status or track changes
 
54
 
 
55
    // Re-read all player data
 
56
    banshee_get_info(player);
 
57
 
 
58
    // Print debug info
 
59
    // dbus_player_debug_print(player);
 
60
 
 
61
    // Process data 
 
62
    dbus_player_process_data(player);
 
63
}
 
64
 
 
65
void banshee_get_app_name(MediaPlayerRec *player) {
 
66
    player->app_name = g_strdup(_("Banshee Media Player"));
 
67
}
 
68
 
 
69
void banshee_state_signal_cb(DBusGProxy *player_proxy, gchar *state, MediaPlayerRec *player) {
 
70
    // State signal from Banshee
 
71
 
 
72
    // state:
 
73
    // "idle"  (quit player)
 
74
    // "loading"
 
75
    // "loaded"
 
76
    // "playing"  (play)
 
77
    // "paused"   (pause)
 
78
 
 
79
    if ((!g_strcmp0(state, "idle")) || // Quit player
 
80
        (!g_strcmp0(state, "playing")) || // Play 
 
81
        (!g_strcmp0(state, "paused"))) {
 
82
 
 
83
        // We do not utilize these state-events at the moment. See the banshee_event_signal_cb() function below.
 
84
 
 
85
        // Re-read all data and inform GUI
 
86
        // banshee_player_status_changed(player);
 
87
    }
 
88
}
 
89
 
 
90
void banshee_event_signal_cb(DBusGProxy *player_proxy, gchar *event, gchar *message, gdouble buffering_percentage, MediaPlayerRec *player) {
 
91
    // Event signal from Banshee
 
92
 
 
93
    // event:
 
94
    // "volume"
 
95
    // "seek"
 
96
    // "statechange"
 
97
    // "requestnexttrack"
 
98
    // "startofstream"
 
99
    // "endofstream"
 
100
 
 
101
    LOG_PLAYER("banshee_event_signal_cb: %s (%s) got event:<%s>\n", player->app_name, player->service_name, event);
 
102
    
 
103
    if (!g_strcmp0(event, "volume")) {
 
104
        // Do nothing
 
105
    } 
 
106
    else if (!g_strcmp0(event, "seek")) {
 
107
        // Do nothing
 
108
    } 
 
109
    else if (!g_strcmp0(event, "requestnexttrack")) {
 
110
        // Do nothing
 
111
    } 
 
112
    else if (!g_strcmp0(event, "statechange")) {
 
113
 
 
114
        // Re-read all data and inform the recorder
 
115
        banshee_player_status_changed(player);
 
116
    }
 
117
    else if (!g_strcmp0(event, "startofstream")) {
 
118
 
 
119
        // Re-read all data and inform the recorder
 
120
        banshee_player_status_changed(player);
 
121
 
 
122
    }
 
123
    else if (!g_strcmp0(event, "endofstream")) {
 
124
 
 
125
        // Track changed. Inform the recorder
 
126
        banshee_player_track_changed(player);
 
127
    }
 
128
}
 
129
 
 
130
gboolean banshee_check_proxy(MediaPlayerRec *player) {
 
131
    // Check/set proxy
 
132
 
 
133
    if (!player) return FALSE;
 
134
 
 
135
    if (!player->proxy) {
 
136
        DBusGConnection *dbus_conn = dbus_player_connect_to_dbus();
 
137
 
 
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");
 
142
    }
 
143
 
 
144
    if (!player->proxy) {
 
145
        LOG_ERROR("banshee_check_proxy: Cannot create DBus proxy for Banshee.\n");
 
146
    }
 
147
 
 
148
    return (player->proxy != NULL);
 
149
}
 
150
 
 
151
void banshee_set_signals(gpointer player_rec, gboolean connect) {
 
152
    // Connect/disconnect signals
 
153
 
 
154
    MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
 
155
    if (!player) return;
 
156
 
 
157
    if (!player->proxy) {
 
158
 
 
159
        if (!banshee_check_proxy(player)) return;
 
160
 
 
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);
 
163
 
 
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);
 
166
    }
 
167
 
 
168
    if (!banshee_check_proxy(player)) return;
 
169
 
 
170
    if (connect) {
 
171
        // Connect signals
 
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);
 
174
    } else  {
 
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);
 
178
    }
 
179
}
 
180
 
 
181
void banshee_hash_str(GHashTable *table, gchar *key, gchar *dest) {
 
182
    dest[0] = '\0';
 
183
 
 
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);
 
187
        }
 
188
}
 
189
 
 
190
gboolean banshee_dbus_string(DBusGProxy *proxy, gchar *method, gchar* dest) {
 
191
    dest[0] = '\0';
 
192
 
 
193
        gchar *str = NULL;
 
194
        GError *error = 0;
 
195
        if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
 
196
                                G_TYPE_INVALID,
 
197
                                G_TYPE_STRING, &str,
 
198
                                G_TYPE_INVALID)) {
 
199
 
 
200
        LOG_ERROR("banshee_dbus_string: Failed to make DBus call %s: %s", method, error ? error->message : "");
 
201
 
 
202
        g_free(str); str = NULL;
 
203
 
 
204
        if (error)
 
205
            g_error_free(error);
 
206
 
 
207
                return FALSE;
 
208
        }
 
209
 
 
210
        str_copy(dest, str, MPRIS_STRLEN-1);
 
211
        dest[MPRIS_STRLEN-1] = '\0';
 
212
        g_free(str);
 
213
        return TRUE;
 
214
}
 
215
 
 
216
gint banshee_dbus_int(DBusGProxy *proxy, const char *method) {
 
217
        gint ret = 0;
 
218
        GError *error = NULL;
 
219
        if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
 
220
                                G_TYPE_INVALID,
 
221
                                G_TYPE_INT, &ret,
 
222
                                G_TYPE_INVALID)) {
 
223
 
 
224
                LOG_ERROR("banshee_dbus_int: Failed to make DBus call %s: %s", method, error ? error->message : "");
 
225
 
 
226
        if (error)
 
227
            g_error_free(error);
 
228
 
 
229
                return 0;
 
230
        }
 
231
 
 
232
        return ret;
 
233
}
 
234
 
 
235
guint banshee_dbus_uint(DBusGProxy *proxy, const char *method) {
 
236
        guint ret = 0;
 
237
        GError *error = NULL;
 
238
        if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
 
239
                                G_TYPE_INVALID,
 
240
                                G_TYPE_UINT, &ret,
 
241
                                G_TYPE_INVALID)) {
 
242
 
 
243
        LOG_ERROR("banshee_dbus_uint: Failed to make DBus call %s: %s", method, error ? error->message : "");
 
244
 
 
245
        if (error)
 
246
            g_error_free(error);
 
247
 
 
248
                return 0;
 
249
        }
 
250
 
 
251
        return ret;
 
252
}
 
253
 
 
254
void banshee_get_info(gpointer player_rec) {
 
255
    MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
 
256
    TrackInfo *tr = &player->track;
 
257
 
 
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;
 
262
        goto LBL_1;
 
263
    }
 
264
 
 
265
    // Check proxy
 
266
    if (!banshee_check_proxy(player)) return;
 
267
 
 
268
        char str[MPRIS_STRLEN];
 
269
 
 
270
    if (!banshee_dbus_string(player->proxy, "GetCurrentState", str)) {
 
271
        // Application has exited/shutdown
 
272
        player->active = FALSE;
 
273
        tr->status = PLAYER_STATUS_STOPPED;
 
274
        goto LBL_1;
 
275
    }
 
276
 
 
277
    if (!g_strcmp0(str, "idle")) {
 
278
        tr->status = PLAYER_STATUS_STOPPED;
 
279
        goto LBL_1;
 
280
 
 
281
    } else if (!g_strcmp0(str, "playing")) {
 
282
        tr->status = PLAYER_STATUS_PLAYING;
 
283
    }
 
284
    else {
 
285
        tr->status = PLAYER_STATUS_PAUSED;
 
286
    }
 
287
 
 
288
    GError *error = NULL;
 
289
    GHashTable* table = NULL;
 
290
 
 
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)) {
 
293
 
 
294
        LOG_ERROR("banshee_get_info: Failed to make DBus call: %s", error ? error->message : "");
 
295
 
 
296
        if (error)
 
297
            g_error_free(error);
 
298
 
 
299
        goto LBL_1;
 
300
    }
 
301
 
 
302
        banshee_hash_str(table, "album", tr->album);
 
303
        banshee_hash_str(table, "artist", tr->artist);
 
304
        banshee_hash_str(table, "name", tr->track);
 
305
 
 
306
    g_hash_table_destroy(table);
 
307
 
 
308
    tr->total_secs = banshee_dbus_uint(player->proxy, "GetLength") / 1000;
 
309
    tr->current_secs = banshee_dbus_uint(player->proxy, "GetPosition") / 1000;
 
310
 
 
311
 LBL_1:
 
312
    ;
 
313
}
 
314
 
 
315
void banshee_start_app(gpointer player_rec) {
 
316
    // Start Banshee
 
317
 
 
318
    MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
 
319
 
 
320
    // Check/set proxy
 
321
    if (!banshee_check_proxy(player)) return;
 
322
 
 
323
    dbus_g_proxy_call_no_reply(player->proxy, "Start", G_TYPE_INVALID);
 
324
}
 
325
 
 
326
/* 
 
327
 VOID:STRING,STRING,DOUBLE (marshal.list:1) 
 
328
 Ref: http://web.archive.org/web/20080501043040/http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices
 
329
 
 
330
 An example:
 
331
 $ echo "VOID:STRING,STRING,DOUBLE" > marshal.list
 
332
 
 
333
 $ glib-genmarshal --prefix=marshal marshal.list --header > sample1.h
 
334
 $ glib-genmarshal --prefix=marshal marshal.list --body > sample1.c
 
335
 
 
336
 See dbus_marshal.c
 
337
*/
 
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)
 
344
{
 
345
    typedef void (*GMarshalFunc_VOID__STRING_STRING_DOUBLE) (gpointer     data1,
 
346
                                                           gpointer     arg_1,
 
347
                                                           gpointer     arg_2,
 
348
                                                           gdouble      arg_3,
 
349
                                                           gpointer     data2);
 
350
    register GMarshalFunc_VOID__STRING_STRING_DOUBLE callback;
 
351
    register GCClosure *cc = (GCClosure*) closure;
 
352
    register gpointer data1, data2;
 
353
 
 
354
    g_return_if_fail (n_param_values == 4);
 
355
 
 
356
    if (G_CCLOSURE_SWAP_DATA (closure)) {
 
357
      data1 = closure->data;
 
358
      data2 = g_value_peek_pointer (param_values + 0);
 
359
    }
 
360
    else {
 
361
      data1 = g_value_peek_pointer (param_values + 0);
 
362
      data2 = closure->data;
 
363
    }
 
364
    callback = (GMarshalFunc_VOID__STRING_STRING_DOUBLE) (marshal_data ? marshal_data : cc->callback);
 
365
 
 
366
    callback (data1,
 
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),
 
370
            data2);
 
371
}
 
372