~matttbe/ubuntu/raring/rhythmbox/lp1010619_RB_2.98

« back to all changes in this revision

Viewing changes to plugins/audiocd/rb-audiocd-info.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-11-06 20:52:57 UTC
  • mfrom: (1.1.67) (214.1.1 quantal-proposed)
  • Revision ID: package-import@ubuntu.com-20121106205257-0btjh8jqley153el
Tags: 2.98-0ubuntu1
* New upstream release (LP: #1060601)
* debian/control.in:
  - Bump minimum glib, gtk, totem-plparser, clutter, and clutter-gst
  - Drop no longer needed musicbrainz dependency
* Refreshed 09_keywords.patch
* Updated 11_fix_cd_pausing.patch with fix from git
* Dropped patches applied in new version:
  - 00git_musicbrainz5.patch
  - 08_CVE-2012-3355.patch
  - dont_free_consumed_floating_gvariant.patch
  - git_scale_click.patch
  - git_crash_during_monitor.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2012 Jonathan Matthew
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2, or (at your option)
 
8
 * any later version.
 
9
 * 
 
10
 * The Rhythmbox authors hereby grant permission for non-GPL compatible
 
11
 * GStreamer plugins to be used and distributed together with GStreamer
 
12
 * and Rhythmbox. This permission is above and beyond the permissions granted
 
13
 * by the GPL license by which Rhythmbox is covered. If you modify this code
 
14
 * you may extend this exception to your version of the code, but you are not
 
15
 * obligated to do so. If you do not wish to do so, delete this exception
 
16
 * statement from your version.
 
17
 *
 
18
 * This program is distributed in the hope that it will be useful,
 
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
 * GNU General Public License for more details.
 
22
 *
 
23
 * You should have received a copy of the GNU General Public License
 
24
 * along with this program; if not, write to the Free Software
 
25
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 
26
 */
 
27
 
 
28
#include "config.h"
 
29
 
 
30
#include <glib/gi18n.h>
 
31
#include <gst/gst.h>
 
32
#include <gst/cdda/gstcddabasesrc.h>
 
33
#include <gio/gio.h>
 
34
 
 
35
#include "rb-audiocd-info.h"
 
36
 
 
37
static gboolean
 
38
read_gst_disc_info (RBAudioCDInfo *info, GError **error)
 
39
{
 
40
        GstElement *source;
 
41
        GstElement *sink;
 
42
        GstElement *pipeline;
 
43
        GstFormat format;
 
44
        GstFormat out_format;
 
45
        GstBus *bus;
 
46
        gint64 num_tracks;
 
47
        gboolean done;
 
48
        int i;
 
49
 
 
50
        source = gst_element_make_from_uri (GST_URI_SRC, "cdda://", NULL);
 
51
        if (source == NULL) {
 
52
                /* if cdparanoiasrc wasn't in base and installed by default
 
53
                 * everywhere, plugin install might be worth trying here.
 
54
                 */
 
55
                g_set_error_literal (error,
 
56
                                     GST_CORE_ERROR,
 
57
                                     GST_CORE_ERROR_MISSING_PLUGIN,
 
58
                                     _("Could not find a GStreamer CD source plugin"));
 
59
                return FALSE;
 
60
        }
 
61
 
 
62
        g_object_set (source, "device", info->device, NULL);
 
63
        pipeline = gst_pipeline_new (NULL);
 
64
        sink = gst_element_factory_make ("fakesink", NULL);
 
65
        gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
 
66
        gst_element_link (source, sink);
 
67
 
 
68
        if (g_object_class_find_property (G_OBJECT_GET_CLASS (source), "paranoia-mode"))
 
69
                g_object_set (source, "paranoia-mode", 0, NULL);
 
70
 
 
71
        gst_element_set_state (pipeline, GST_STATE_PAUSED);
 
72
 
 
73
        bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
 
74
        done = FALSE;
 
75
        while (done == FALSE) {
 
76
                GstMessage *msg;
 
77
                GstTagList *tags;
 
78
 
 
79
                msg = gst_bus_timed_pop (bus, 3 * GST_SECOND);
 
80
                if (msg == NULL)
 
81
                        break;
 
82
 
 
83
                switch (GST_MESSAGE_TYPE (msg)) {
 
84
                case GST_MESSAGE_TAG:
 
85
                        gst_message_parse_tag (msg, &tags);
 
86
 
 
87
                        gst_tag_list_get_string (tags,
 
88
                                                 GST_TAG_CDDA_MUSICBRAINZ_DISCID,
 
89
                                                 &info->musicbrainz_disc_id);
 
90
                        gst_tag_list_get_string (tags,
 
91
                                                 GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL,
 
92
                                                 &info->musicbrainz_full_disc_id);
 
93
 
 
94
                        gst_tag_list_free (tags);
 
95
                        break;
 
96
 
 
97
                case GST_MESSAGE_STATE_CHANGED:
 
98
                        if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline)) {
 
99
                                GstState oldstate;
 
100
                                GstState newstate;
 
101
                                GstState pending;
 
102
 
 
103
                                gst_message_parse_state_changed (msg, &oldstate, &newstate, &pending);
 
104
                                if (newstate == GST_STATE_PAUSED && pending == GST_STATE_VOID_PENDING)
 
105
                                        done = TRUE;
 
106
                        }
 
107
                        break;
 
108
                case GST_MESSAGE_ERROR:
 
109
                        gst_message_parse_error (msg, error, NULL);
 
110
                        done = TRUE;
 
111
                        break;
 
112
                default:
 
113
                        break;
 
114
                }
 
115
 
 
116
                gst_message_unref (msg);
 
117
        }
 
118
 
 
119
        if (*error == NULL) {
 
120
                format = gst_format_get_by_nick ("track");
 
121
                out_format = format;
 
122
                gst_element_query_duration (source, &out_format, &num_tracks);
 
123
                info->num_tracks = num_tracks;
 
124
 
 
125
                info->tracks = g_new0 (RBAudioCDTrack, num_tracks);
 
126
                for (i = 0; i < num_tracks; i++) {
 
127
                        RBAudioCDTrack *track = &info->tracks[i];
 
128
                        GstCddaBaseSrcTrack *gst_track = &GST_CDDA_BASE_SRC (source)->tracks[i];
 
129
                        guint64 duration = 0;
 
130
 
 
131
                        track->is_audio = gst_track->is_audio;
 
132
                        track->track_num = gst_track->num;
 
133
 
 
134
                        gst_tag_list_get_uint64 (gst_track->tags, GST_TAG_DURATION, &duration);
 
135
                        track->duration = (duration / GST_MSECOND);
 
136
                }
 
137
        }
 
138
 
 
139
        gst_element_set_state (pipeline, GST_STATE_NULL);
 
140
        gst_object_unref (bus);
 
141
        gst_object_unref (pipeline);
 
142
        return (*error == NULL);
 
143
}
 
144
 
 
145
static void
 
146
read_gvfs_disc_info (RBAudioCDInfo *info)
 
147
{
 
148
        GFile *cdda;
 
149
        GFileInfo *fileinfo;
 
150
        GFileEnumerator *tracks;
 
151
        const char *attr;
 
152
        char *uri;
 
153
        char *dev;
 
154
 
 
155
        dev = g_path_get_basename (info->device);
 
156
        uri = g_strdup_printf ("cdda://%s", dev);
 
157
        g_free (dev);
 
158
 
 
159
        cdda = g_file_new_for_uri (uri);
 
160
        g_free (uri);
 
161
 
 
162
        fileinfo = g_file_query_info (cdda, "xattr::*", G_FILE_QUERY_INFO_NONE, NULL, NULL);
 
163
        if (fileinfo == NULL) {
 
164
                g_object_unref (cdda);
 
165
                return;
 
166
        }
 
167
 
 
168
        attr = g_file_info_get_attribute_string (fileinfo, "xattr::org.gnome.audio.title");
 
169
        if (attr != NULL) {
 
170
                info->album = g_strdup (attr);
 
171
        }
 
172
        attr = g_file_info_get_attribute_string (fileinfo, "xattr::org.gnome.audio.artist");
 
173
        if (attr != NULL) {
 
174
                info->album_artist = g_strdup (attr);
 
175
        }
 
176
        attr = g_file_info_get_attribute_string (fileinfo, "xattr::org.gnome.audio.genre");
 
177
        if (attr != NULL) {
 
178
                info->genre = g_strdup (attr);
 
179
        }
 
180
 
 
181
        tracks = g_file_enumerate_children (cdda, G_FILE_ATTRIBUTE_STANDARD_NAME ",xattr::*", G_FILE_QUERY_INFO_NONE, NULL, NULL);
 
182
        if (tracks != NULL) {
 
183
                for (fileinfo = g_file_enumerator_next_file (tracks, NULL, NULL);
 
184
                     fileinfo != NULL;
 
185
                     fileinfo = g_file_enumerator_next_file (tracks, NULL, NULL)) {
 
186
                        const char *name;
 
187
                        const char *attr;
 
188
                        int track_num;
 
189
 
 
190
                        name = g_file_info_get_name (fileinfo);
 
191
                        if (name == NULL || sscanf (name, "Track %d.wav", &track_num) != 1) {
 
192
                                continue;
 
193
                        }
 
194
 
 
195
                        if (track_num < 1 || track_num > info->num_tracks) {
 
196
                                continue;
 
197
                        }
 
198
                        g_assert (track_num == info->tracks[track_num-1].track_num);
 
199
 
 
200
                        attr = g_file_info_get_attribute_string (fileinfo, "xattr::org.gnome.audio.title");
 
201
                        if (attr != NULL) {
 
202
                                info->tracks[track_num - 1].title = g_strdup (attr);
 
203
                        }
 
204
                        attr = g_file_info_get_attribute_string (fileinfo, "xattr::org.gnome.audio.artist");
 
205
                        if (attr != NULL) {
 
206
                                info->tracks[track_num - 1].artist = g_strdup (attr);
 
207
                        }
 
208
                }
 
209
        }
 
210
        g_object_unref (tracks);
 
211
 
 
212
        g_object_unref (cdda);
 
213
}
 
214
 
 
215
static void
 
216
audiocd_info_thread (GSimpleAsyncResult *result, GObject *object, GCancellable *cancellable)
 
217
{
 
218
        RBAudioCDInfo *info;
 
219
        GError *error = NULL;
 
220
 
 
221
        info = g_simple_async_result_get_op_res_gpointer (result);
 
222
 
 
223
        if (read_gst_disc_info (info, &error)) {
 
224
                read_gvfs_disc_info (info);
 
225
        } else {
 
226
                rb_audiocd_info_free (info);
 
227
                g_simple_async_result_set_op_res_gpointer (result, NULL, NULL);
 
228
                g_simple_async_result_take_error (result, error);
 
229
        }
 
230
}
 
231
 
 
232
void
 
233
rb_audiocd_info_free (RBAudioCDInfo *info)
 
234
{
 
235
        int i;
 
236
 
 
237
        g_free (info->device);
 
238
        g_free (info->musicbrainz_disc_id);
 
239
        g_free (info->musicbrainz_full_disc_id);
 
240
        g_free (info->album);
 
241
        g_free (info->genre);
 
242
        g_free (info->album_artist);
 
243
 
 
244
        for (i = 0; i < info->num_tracks; i++) {
 
245
                g_free (info->tracks[i].artist);
 
246
                g_free (info->tracks[i].title);
 
247
        }
 
248
        g_free (info->tracks);
 
249
        g_free (info);
 
250
}
 
251
 
 
252
void
 
253
rb_audiocd_info_get (const char *device,
 
254
                     GCancellable *cancellable,
 
255
                     GAsyncReadyCallback callback,
 
256
                     gpointer user_data)
 
257
{
 
258
        GSimpleAsyncResult *result;
 
259
        RBAudioCDInfo *info;
 
260
 
 
261
        result = g_simple_async_result_new (NULL, callback, user_data, rb_audiocd_info_get);
 
262
        g_simple_async_result_set_check_cancellable (result, cancellable);
 
263
 
 
264
        info = g_new0 (RBAudioCDInfo, 1);
 
265
        info->device = g_strdup (device);
 
266
        g_simple_async_result_set_op_res_gpointer (result, info, NULL);
 
267
 
 
268
        g_simple_async_result_run_in_thread (result, audiocd_info_thread, G_PRIORITY_DEFAULT, cancellable);
 
269
}
 
270
 
 
271
RBAudioCDInfo *
 
272
rb_audiocd_info_finish (GAsyncResult *result,
 
273
                        GError **error)
 
274
{
 
275
        g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, rb_audiocd_info_get),
 
276
                              NULL);
 
277
        if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
 
278
                return NULL;
 
279
 
 
280
        return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
281
}