~audio-recorder/audio-recorder/trunk

« back to all changes in this revision

Viewing changes to src/dbus-banshee.c

  • Committer: Osmo Antero
  • Date: 2012-04-18 19:22:01 UTC
  • Revision ID: osmoma@gmail.com-20120418192201-ejjs6ikv7o4aznbi
New media-player interface that's based on the MediaPlayer2 standard. See src/dbus-mpris2.c.

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
 
// Read 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_start(MediaPlayerRec *player) {
36
 
    // Called when Banshee player starts a new track
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_PLAYING;
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_track_stop(MediaPlayerRec *player) {
53
 
    // Called when Banshee player ends a track
54
 
 
55
 
    // Re-read all player data
56
 
    banshee_get_info(player);
57
 
 
58
 
    // Set track changed signal
59
 
    TrackInfo *tr = &player->track;
60
 
    tr->status = PLAYER_STATUS_STOPPED;
61
 
 
62
 
    // Print debug info
63
 
    dbus_player_debug_print(player);
64
 
 
65
 
    // Process data
66
 
    dbus_player_process_data(player);
67
 
}
68
 
 
69
 
/*
70
 
void banshee_player_track_changed(MediaPlayerRec *player) {
71
 
    // Called when track changes
72
 
 
73
 
    // Re-read all player data
74
 
    banshee_get_info(player);
75
 
 
76
 
    // Set track changed signal
77
 
    TrackInfo *tr = &player->track;
78
 
    tr->status = PLAYER_STATUS_TRACK_CHANGE;
79
 
 
80
 
    // Print debug info
81
 
    dbus_player_debug_print(player);
82
 
 
83
 
    // Process data
84
 
    dbus_player_process_data(player);
85
 
}
86
 
*/
87
 
 
88
 
void banshee_player_status_changed(MediaPlayerRec *player) {
89
 
    // Called when player's status or track changes
90
 
 
91
 
    // Re-read all player data
92
 
    banshee_get_info(player);
93
 
 
94
 
    // Print debug info
95
 
    // dbus_player_debug_print(player);
96
 
 
97
 
    // Process data
98
 
    dbus_player_process_data(player);
99
 
}
100
 
 
101
 
void banshee_get_app_name(MediaPlayerRec *player) {
102
 
    // Name of the Banshee media player.
103
 
    player->app_name = g_strdup(_("Banshee Media Player"));
104
 
}
105
 
 
106
 
void banshee_state_signal_cb(DBusGProxy *player_proxy, gchar *state, MediaPlayerRec *player) {
107
 
    // State signal from Banshee
108
 
 
109
 
    // state:
110
 
    // "idle"  (quit player)
111
 
    // "loading"
112
 
    // "loaded"
113
 
    // "playing"  (play)
114
 
    // "paused"   (pause)
115
 
 
116
 
    // LOG_PLAYER("banshee_state_signal_cb: %s (%s) got state:<%s>\n", player->app_name, player->service_name, state);
117
 
 
118
 
    if ((!g_strcmp0(state, "idle")) || // Quit player
119
 
            (!g_strcmp0(state, "playing")) || // Play
120
 
            (!g_strcmp0(state, "paused"))) {
121
 
 
122
 
        // We do not utilize these state-events at the moment. See the banshee_event_signal_cb() function below.
123
 
 
124
 
        // Re-read all data and inform GUI
125
 
        // banshee_player_status_changed(player);
126
 
    }
127
 
}
128
 
 
129
 
void banshee_event_signal_cb(DBusGProxy *player_proxy, gchar *event, gchar *message, gdouble buffering_percentage, MediaPlayerRec *player) {
130
 
    // Event signal from Banshee
131
 
 
132
 
    // event:
133
 
    // "volume"
134
 
    // "seek"
135
 
    // "statechange"
136
 
    // "requestnexttrack"
137
 
    // "startofstream"
138
 
    // "endofstream"
139
 
 
140
 
    LOG_PLAYER("banshee_event_signal_cb: %s (%s) got event:<%s>\n", player->app_name, player->service_name, event);
141
 
 
142
 
    if (!g_strcmp0(event, "volume")) {
143
 
        // Do nothing
144
 
    } else if (!g_strcmp0(event, "seek")) {
145
 
        // Do nothing
146
 
    } else if (!g_strcmp0(event, "requestnexttrack")) {
147
 
        // Do nothing
148
 
    } else if (!g_strcmp0(event, "statechange")) {
149
 
 
150
 
        // Re-read all data and inform the recorder
151
 
        banshee_player_status_changed(player);
152
 
 
153
 
    } else if (!g_strcmp0(event, "startofstream")) {
154
 
 
155
 
        // Stop and start of a new stream/track. Inform the recorder
156
 
        banshee_player_track_stop(player);
157
 
        banshee_player_track_start(player);
158
 
 
159
 
    } else if (!g_strcmp0(event, "endofstream")) {
160
 
 
161
 
        // End of track/stream. Inform the recorder
162
 
        banshee_player_track_stop(player);
163
 
    }
164
 
}
165
 
 
166
 
gboolean banshee_check_proxy(MediaPlayerRec *player) {
167
 
    // Check/set proxy
168
 
 
169
 
    if (!player) return FALSE;
170
 
 
171
 
    if (!player->proxy) {
172
 
        DBusGConnection *dbus_conn = dbus_player_connect_to_dbus();
173
 
 
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");
178
 
    }
179
 
 
180
 
    if (!player->proxy) {
181
 
        LOG_ERROR("banshee_check_proxy: Cannot create DBus proxy for Banshee.\n");
182
 
    }
183
 
 
184
 
    return (player->proxy != NULL);
185
 
}
186
 
 
187
 
void banshee_set_signals(gpointer player_rec, gboolean connect) {
188
 
    // Connect/disconnect signals
189
 
 
190
 
    MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
191
 
    if (!player) return;
192
 
 
193
 
    if (!player->proxy) {
194
 
 
195
 
        if (!banshee_check_proxy(player)) return;
196
 
 
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);
199
 
 
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);
202
 
    }
203
 
 
204
 
    if (!banshee_check_proxy(player)) return;
205
 
 
206
 
    if (connect) {
207
 
        // Connect signals
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);
210
 
    } else  {
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);
214
 
    }
215
 
}
216
 
 
217
 
void banshee_hash_str(GHashTable *table, gchar *key, gchar *dest) {
218
 
    dest[0] = '\0';
219
 
 
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);
223
 
    }
224
 
}
225
 
 
226
 
gboolean banshee_dbus_string(DBusGProxy *proxy, gchar *method, gchar* dest) {
227
 
    dest[0] = '\0';
228
 
 
229
 
    gchar *str = NULL;
230
 
    GError *error = 0;
231
 
    if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
232
 
                                         G_TYPE_INVALID,
233
 
                                         G_TYPE_STRING, &str,
234
 
                                         G_TYPE_INVALID)) {
235
 
 
236
 
        LOG_ERROR("banshee_dbus_string: Failed to make DBus call %s: %s", method, error ? error->message : "");
237
 
 
238
 
        g_free(str);
239
 
        str = NULL;
240
 
 
241
 
        if (error)
242
 
            g_error_free(error);
243
 
 
244
 
        return FALSE;
245
 
    }
246
 
 
247
 
    str_copy(dest, str, MPRIS_STRLEN-1);
248
 
    dest[MPRIS_STRLEN-1] = '\0';
249
 
    g_free(str);
250
 
    return TRUE;
251
 
}
252
 
 
253
 
gint banshee_dbus_int(DBusGProxy *proxy, const char *method) {
254
 
    gint ret = 0;
255
 
    GError *error = NULL;
256
 
    if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
257
 
                                         G_TYPE_INVALID,
258
 
                                         G_TYPE_INT, &ret,
259
 
                                         G_TYPE_INVALID)) {
260
 
 
261
 
        LOG_ERROR("banshee_dbus_int: Failed to make DBus call %s: %s", method, error ? error->message : "");
262
 
 
263
 
        if (error)
264
 
            g_error_free(error);
265
 
 
266
 
        return 0;
267
 
    }
268
 
 
269
 
    return ret;
270
 
}
271
 
 
272
 
guint banshee_dbus_uint(DBusGProxy *proxy, const char *method) {
273
 
    guint ret = 0;
274
 
    GError *error = NULL;
275
 
    if (!dbus_g_proxy_call_with_timeout (proxy, method, DBUS_MPRIS_TIMEOUT, &error,
276
 
                                         G_TYPE_INVALID,
277
 
                                         G_TYPE_UINT, &ret,
278
 
                                         G_TYPE_INVALID)) {
279
 
 
280
 
        LOG_ERROR("banshee_dbus_uint: Failed to make DBus call %s: %s", method, error ? error->message : "");
281
 
 
282
 
        if (error)
283
 
            g_error_free(error);
284
 
 
285
 
        return 0;
286
 
    }
287
 
 
288
 
    return ret;
289
 
}
290
 
 
291
 
void banshee_get_info(gpointer player_rec) {
292
 
    MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
293
 
    TrackInfo *tr = &player->track;
294
 
 
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;
299
 
        goto LBL_1;
300
 
    }
301
 
 
302
 
    // Check proxy
303
 
    if (!banshee_check_proxy(player)) return;
304
 
 
305
 
    char str[MPRIS_STRLEN];
306
 
 
307
 
    if (!banshee_dbus_string(player->proxy, "GetCurrentState", str)) {
308
 
        // Application has exited/shutdown
309
 
        player->active = FALSE;
310
 
        tr->status = PLAYER_STATUS_STOPPED;
311
 
        goto LBL_1;
312
 
    }
313
 
 
314
 
    if (!g_strcmp0(str, "idle")) {
315
 
        tr->status = PLAYER_STATUS_STOPPED;
316
 
        goto LBL_1;
317
 
 
318
 
    } else if (!g_strcmp0(str, "playing")) {
319
 
        tr->status = PLAYER_STATUS_PLAYING;
320
 
    } else {
321
 
        tr->status = PLAYER_STATUS_PAUSED;
322
 
    }
323
 
 
324
 
    GError *error = NULL;
325
 
    GHashTable* table = NULL;
326
 
 
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)) {
329
 
 
330
 
        LOG_ERROR("banshee_get_info: Failed to make DBus call: %s", error ? error->message : "");
331
 
 
332
 
        if (error)
333
 
            g_error_free(error);
334
 
 
335
 
        goto LBL_1;
336
 
    }
337
 
 
338
 
    banshee_hash_str(table, "album", tr->album);
339
 
    banshee_hash_str(table, "artist", tr->artist);
340
 
    banshee_hash_str(table, "name", tr->track);
341
 
 
342
 
    g_hash_table_destroy(table);
343
 
 
344
 
    tr->total_secs = banshee_dbus_uint(player->proxy, "GetLength") / 1000;
345
 
    tr->current_secs = banshee_dbus_uint(player->proxy, "GetPosition") / 1000;
346
 
 
347
 
LBL_1:
348
 
    ;
349
 
}
350
 
 
351
 
void banshee_start_app(gpointer player_rec) {
352
 
    // Start Banshee
353
 
 
354
 
    MediaPlayerRec *player = (MediaPlayerRec*)player_rec;
355
 
 
356
 
    // Check/set proxy
357
 
    if (!banshee_check_proxy(player)) return;
358
 
 
359
 
    dbus_g_proxy_call_no_reply(player->proxy, "Start", G_TYPE_INVALID);
360
 
}
361
 
 
362
 
/*
363
 
 VOID:STRING,STRING,DOUBLE (marshal.list:1)
364
 
 Ref: http://web.archive.org/web/20080501043040/http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices
365
 
 
366
 
 An example:
367
 
 $ echo "VOID:STRING,STRING,DOUBLE" > marshal.list
368
 
 
369
 
 $ glib-genmarshal --prefix=marshal marshal.list --header > sample1.h
370
 
 $ glib-genmarshal --prefix=marshal marshal.list --body > sample1.c
371
 
 
372
 
 See dbus_marshal.c
373
 
*/
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,
381
 
            gpointer     arg_1,
382
 
            gpointer     arg_2,
383
 
            gdouble      arg_3,
384
 
            gpointer     data2);
385
 
    register GMarshalFunc_VOID__STRING_STRING_DOUBLE callback;
386
 
    register GCClosure *cc = (GCClosure*) closure;
387
 
    register gpointer data1, data2;
388
 
 
389
 
    g_return_if_fail (n_param_values == 4);
390
 
 
391
 
    if (G_CCLOSURE_SWAP_DATA (closure)) {
392
 
        data1 = closure->data;
393
 
        data2 = g_value_peek_pointer (param_values + 0);
394
 
    } else {
395
 
        data1 = g_value_peek_pointer (param_values + 0);
396
 
        data2 = closure->data;
397
 
    }
398
 
    callback = (GMarshalFunc_VOID__STRING_STRING_DOUBLE) (marshal_data ? marshal_data : cc->callback);
399
 
 
400
 
    callback (data1,
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),
404
 
              data2);
405
 
}
406