~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to player/rb-recorder-gst.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 
2
/*
 
3
 * arch-tag: Implementation of GStreamer recorder backend
 
4
 *
 
5
 * Copyright (C) 2004-2005 William Jon McCann <mccann@jhu.edu>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License as
 
9
 * published by the Free Software Foundation; either version 2 of the
 
10
 * License, or (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public
 
18
 * License along with this program; if not, write to the
 
19
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
20
 * Boston, MA 02111-1307, USA.
 
21
 */
 
22
 
 
23
#include <config.h>
 
24
#include <unistd.h>
 
25
#include <string.h>
 
26
#include <math.h>
 
27
#include <time.h>
 
28
#include <sys/vfs.h>
 
29
#include <sys/types.h>
 
30
#include <sys/stat.h>
 
31
#include <fcntl.h>
 
32
 
 
33
#include <gst/gst.h>
 
34
#include <gst/gconf/gconf.h>
 
35
#include <gst/play/play.h>
 
36
#include <glib/gi18n.h>
 
37
#include <libgnomevfs/gnome-vfs-utils.h>
 
38
#include <nautilus-burn-recorder.h>
 
39
 
 
40
#include "rb-recorder.h"
 
41
#include "rb-recorder-marshal.h"
 
42
 
 
43
#include "rb-debug.h"
 
44
 
 
45
static void rb_recorder_class_init (RBRecorderClass *klass);
 
46
static void rb_recorder_init       (RBRecorder      *recorder);
 
47
static void rb_recorder_finalize   (GObject         *object);
 
48
 
 
49
struct _RBRecorderPrivate {
 
50
        char       *src_uri;
 
51
        char       *dest_file;
 
52
        char       *tmp_dir;
 
53
        
 
54
        GstElement *pipeline;
 
55
        
 
56
        GstElement *src;
 
57
        GstPad     *src_pad;
 
58
        GstElement *decoder;
 
59
        GstElement *typefind;
 
60
        GstElement *audioconvert;
 
61
        GstElement *audioscale;
 
62
        GstElement *encoder;
 
63
        GstElement *sink;
 
64
 
 
65
        guint       idle_id;
 
66
        guint       error_signal_id;
 
67
        guint       eos_signal_id;
 
68
        guint       tick_timeout_id;
 
69
 
 
70
        GTimer     *start_timer;
 
71
        guint64     start_pos;
 
72
 
 
73
        double      progress;
 
74
 
 
75
        GList      *tracks;
 
76
 
 
77
        NautilusBurnDrive    *drive;
 
78
        NautilusBurnRecorder *recorder;
 
79
 
 
80
        gboolean    playing;
 
81
 
 
82
        GError     *error;
 
83
};
 
84
 
 
85
typedef enum {
 
86
        EOS,
 
87
        ACTION_CHANGED,
 
88
        TRACK_PROGRESS_CHANGED,
 
89
        BURN_PROGRESS_CHANGED,
 
90
        INSERT_MEDIA_REQUEST,
 
91
        WARN_DATA_LOSS,
 
92
        ERROR,
 
93
        LAST_SIGNAL
 
94
} RBRecorderSignalType;
 
95
 
 
96
typedef struct {
 
97
        RBRecorder *object;
 
98
        GError     *error;
 
99
        GValue     *info;
 
100
} RBRecorderSignal;
 
101
 
 
102
static guint rb_recorder_signals [LAST_SIGNAL] = { 0 };
 
103
 
 
104
static GObjectClass *parent_class = NULL;
 
105
 
 
106
gboolean
 
107
rb_recorder_enabled (void)
 
108
{
 
109
        char    *device  = rb_recorder_get_default_device ();
 
110
        gboolean enabled = (device != NULL);
 
111
 
 
112
        g_free (device);
 
113
 
 
114
        return enabled;
 
115
}
 
116
 
 
117
GQuark
 
118
rb_recorder_error_quark (void)
 
119
{
 
120
        static GQuark quark = 0;
 
121
        if (!quark)
 
122
                quark = g_quark_from_static_string ("rb_recorder_error");
 
123
 
 
124
        return quark;
 
125
}
 
126
 
 
127
G_DEFINE_TYPE(RBRecorder, rb_recorder, G_TYPE_OBJECT)
 
128
 
 
129
static void
 
130
rb_recorder_class_init (RBRecorderClass *klass)
 
131
{
 
132
        GObjectClass *object_class;
 
133
 
 
134
        parent_class = g_type_class_peek_parent (klass);
 
135
        object_class = (GObjectClass *) klass;
 
136
 
 
137
        object_class->finalize = rb_recorder_finalize;
 
138
 
 
139
        rb_recorder_signals [EOS] =
 
140
                g_signal_new ("eos",
 
141
                              G_TYPE_FROM_CLASS (klass),
 
142
                              G_SIGNAL_RUN_LAST,
 
143
                              0,
 
144
                              NULL, NULL,
 
145
                              g_cclosure_marshal_VOID__VOID,
 
146
                              G_TYPE_NONE,
 
147
                              0);
 
148
        rb_recorder_signals [TRACK_PROGRESS_CHANGED] =
 
149
                g_signal_new ("track-progress-changed",
 
150
                              G_TYPE_FROM_CLASS (klass),
 
151
                              G_SIGNAL_RUN_LAST,
 
152
                              0,
 
153
                              NULL, NULL,
 
154
                              rb_recorder_marshal_VOID__DOUBLE_LONG,
 
155
                              G_TYPE_NONE,
 
156
                              2,
 
157
                              G_TYPE_DOUBLE,
 
158
                              G_TYPE_LONG);
 
159
        rb_recorder_signals [BURN_PROGRESS_CHANGED] =
 
160
                g_signal_new ("burn-progress-changed",
 
161
                              G_TYPE_FROM_CLASS (klass),
 
162
                              G_SIGNAL_RUN_LAST,
 
163
                              0,
 
164
                              NULL, NULL,
 
165
                              rb_recorder_marshal_VOID__DOUBLE_LONG,
 
166
                              G_TYPE_NONE,
 
167
                              2,
 
168
                              G_TYPE_DOUBLE,
 
169
                              G_TYPE_LONG);
 
170
        rb_recorder_signals [ACTION_CHANGED] =
 
171
                g_signal_new ("action-changed",
 
172
                              G_TYPE_FROM_CLASS (klass),
 
173
                              G_SIGNAL_RUN_LAST,
 
174
                              0,
 
175
                              NULL, NULL,
 
176
                              g_cclosure_marshal_VOID__INT,
 
177
                              G_TYPE_NONE,
 
178
                              1,
 
179
                              G_TYPE_INT);
 
180
        rb_recorder_signals [INSERT_MEDIA_REQUEST] =
 
181
                g_signal_new ("insert-media-request",
 
182
                              G_TYPE_FROM_CLASS (klass),
 
183
                              G_SIGNAL_RUN_LAST,
 
184
                              0,
 
185
                              NULL, NULL,
 
186
                              rb_recorder_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
 
187
                              G_TYPE_BOOLEAN,
 
188
                              3,
 
189
                              G_TYPE_BOOLEAN,
 
190
                              G_TYPE_BOOLEAN,
 
191
                              G_TYPE_BOOLEAN);
 
192
        rb_recorder_signals [WARN_DATA_LOSS] =
 
193
                g_signal_new ("warn-data-loss",
 
194
                              G_TYPE_FROM_CLASS (klass),
 
195
                              G_SIGNAL_RUN_LAST,
 
196
                              0,
 
197
                              NULL, NULL,
 
198
                              rb_recorder_marshal_INT__VOID,
 
199
                              G_TYPE_INT, 0);
 
200
        rb_recorder_signals [ERROR] =
 
201
                g_signal_new ("error",
 
202
                              G_TYPE_FROM_CLASS (klass),
 
203
                              G_SIGNAL_RUN_LAST,
 
204
                              0,
 
205
                              NULL, NULL,
 
206
                              g_cclosure_marshal_VOID__POINTER,
 
207
                              G_TYPE_NONE,
 
208
                              1,
 
209
                              G_TYPE_POINTER);
 
210
}
 
211
 
 
212
static void
 
213
rb_recorder_init (RBRecorder *recorder)
 
214
{
 
215
        recorder->priv = g_new0 (RBRecorderPrivate, 1);
 
216
 
 
217
        recorder->priv->tmp_dir = g_strdup (g_get_tmp_dir ());
 
218
}
 
219
 
 
220
static void
 
221
rb_recorder_gst_free_pipeline (RBRecorder *recorder)
 
222
{
 
223
        rb_debug ("Freeing rb_recorder pipeline");
 
224
 
 
225
        if (recorder->priv->pipeline == NULL)
 
226
                return;
 
227
 
 
228
        if (recorder->priv->tick_timeout_id > 0) {
 
229
                g_source_remove (recorder->priv->tick_timeout_id);
 
230
                recorder->priv->tick_timeout_id = 0;
 
231
                if (recorder->priv->start_timer) {
 
232
                        g_timer_destroy (recorder->priv->start_timer);
 
233
                        recorder->priv->start_timer = NULL;
 
234
                }
 
235
        }
 
236
 
 
237
        if (recorder->priv->idle_id > 0) {
 
238
                g_source_remove (recorder->priv->idle_id);
 
239
                recorder->priv->idle_id = 0;
 
240
        }
 
241
 
 
242
        if (recorder->priv->error_signal_id > 0) {
 
243
                if (g_signal_handler_is_connected (G_OBJECT (recorder->priv->pipeline),
 
244
                                                   recorder->priv->error_signal_id))
 
245
                        g_signal_handler_disconnect (G_OBJECT (recorder->priv->pipeline),
 
246
                                                     recorder->priv->error_signal_id);
 
247
                recorder->priv->error_signal_id = 0;
 
248
        }
 
249
 
 
250
        if (recorder->priv->eos_signal_id > 0) {
 
251
                if (g_signal_handler_is_connected (G_OBJECT (recorder->priv->pipeline),
 
252
                                                   recorder->priv->eos_signal_id))
 
253
                        g_signal_handler_disconnect (G_OBJECT (recorder->priv->pipeline),
 
254
                                                     recorder->priv->eos_signal_id);
 
255
                recorder->priv->eos_signal_id = 0;
 
256
        }
 
257
 
 
258
        gst_object_unref (GST_OBJECT (recorder->priv->pipeline));
 
259
        recorder->priv->pipeline = NULL;
 
260
}
 
261
 
 
262
static gboolean
 
263
add_track (RBRecorder *recorder,
 
264
           const char *cdtext)
 
265
{
 
266
        NautilusBurnRecorderTrack *track;
 
267
        char                      *filename;
 
268
 
 
269
        g_return_val_if_fail (RB_IS_RECORDER (recorder), FALSE);
 
270
 
 
271
        filename = g_strdup (recorder->priv->dest_file);
 
272
 
 
273
        track = g_new0 (NautilusBurnRecorderTrack, 1);
 
274
 
 
275
        track->type = NAUTILUS_BURN_RECORDER_TRACK_TYPE_AUDIO;
 
276
        track->contents.audio.filename = filename;
 
277
        if (cdtext)
 
278
                track->contents.audio.cdtext = g_strdup (cdtext);
 
279
 
 
280
        recorder->priv->tracks = g_list_append (recorder->priv->tracks, track);
 
281
 
 
282
        return TRUE;
 
283
}
 
284
 
 
285
static void
 
286
eos_cb (GstElement *element,
 
287
        RBRecorder *recorder)
 
288
{
 
289
        rb_debug ("EOS");
 
290
 
 
291
        if (recorder->priv->pipeline)
 
292
                gst_element_set_state (recorder->priv->pipeline, GST_STATE_NULL);
 
293
 
 
294
        g_signal_emit (G_OBJECT (recorder), rb_recorder_signals [EOS], 0);
 
295
}
 
296
 
 
297
static gboolean
 
298
error_signal_idle (RBRecorderSignal *signal)
 
299
{
 
300
        g_signal_emit (G_OBJECT (signal->object),
 
301
                       rb_recorder_signals [ERROR],
 
302
                       0,
 
303
                       signal->error);
 
304
 
 
305
        /* close if not already closing */
 
306
        if (signal->object->priv->src_uri != NULL)
 
307
                rb_recorder_close (signal->object, NULL);
 
308
 
 
309
        g_object_unref (signal->object);
 
310
        g_error_free (signal->error);
 
311
        g_free (signal);
 
312
 
 
313
        return FALSE;
 
314
}
 
315
 
 
316
static void
 
317
rb_recorder_gst_signal_error (RBRecorder *recorder,
 
318
                              const char *msg)
 
319
{
 
320
        RBRecorderSignal *signal;
 
321
 
 
322
        signal = g_new0 (RBRecorderSignal, 1);
 
323
        signal->object = recorder;
 
324
        signal->error = g_error_new_literal (RB_RECORDER_ERROR,
 
325
                                             RB_RECORDER_ERROR_GENERAL,
 
326
                                             msg);
 
327
        g_object_ref (recorder);
 
328
 
 
329
        g_idle_add ((GSourceFunc)error_signal_idle, signal);
 
330
}
 
331
 
 
332
static void
 
333
error_cb (GstElement      *element,
 
334
          GstElement      *source,
 
335
          GError          *error,
 
336
          gchar           *debug,
 
337
          RBRecorder      *recorder)
 
338
{
 
339
        rb_debug ("Error");
 
340
 
 
341
        rb_recorder_gst_signal_error (recorder, error->message);
 
342
}
 
343
 
 
344
static void
 
345
rb_recorder_construct (RBRecorder *recorder,
 
346
                       const char *uri,
 
347
                       GError    **error)
 
348
{
 
349
        char    *element_name = NULL;
 
350
        GstCaps *filtercaps;
 
351
 
 
352
#define MAKE_ELEMENT_OR_LOSE(NAME, NICE) G_STMT_START {                 \
 
353
                element_name = #NAME ;                                  \
 
354
                rb_debug ("Constructing element \"" #NICE "\"");        \
 
355
                recorder->priv->NICE = gst_element_factory_make (#NAME, #NICE); \
 
356
                if (!recorder->priv->NICE)                              \
 
357
                        goto missing_element;                           \
 
358
        } G_STMT_END
 
359
 
 
360
        rb_recorder_gst_free_pipeline (recorder);
 
361
 
 
362
        /* The recording pipeline looks like:
 
363
         *  { src ! spider ! audioconvert ! audioscale
 
364
         *    ! audio/x-raw-int,rate=44100,width=16,depth=16 ! wavenc ! sink }
 
365
         */
 
366
 
 
367
        recorder->priv->pipeline = gst_pipeline_new ("pipeline");
 
368
        if (!recorder->priv->pipeline) {
 
369
                g_set_error (error,
 
370
                             RB_RECORDER_ERROR,
 
371
                             RB_RECORDER_ERROR_GENERAL,
 
372
                             _("Failed to create pipeline"));
 
373
                rb_recorder_gst_free_pipeline (recorder);
 
374
                return;
 
375
        }
 
376
 
 
377
        recorder->priv->error_signal_id =
 
378
                g_signal_connect_object (G_OBJECT (recorder->priv->pipeline),
 
379
                                         "error",
 
380
                                         G_CALLBACK (error_cb),
 
381
                                         recorder, 0);
 
382
 
 
383
        /* Construct elements */
 
384
 
 
385
        /* The source */
 
386
 
 
387
        MAKE_ELEMENT_OR_LOSE(gnomevfssrc, src);
 
388
        gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->src);
 
389
 
 
390
        recorder->priv->src_pad = gst_element_get_pad (recorder->priv->src, "src");
 
391
        g_assert (recorder->priv->src_pad); /* TODO: GError */
 
392
 
 
393
        /* The queue */
 
394
 
 
395
        MAKE_ELEMENT_OR_LOSE(typefind, typefind);
 
396
        gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->typefind);
 
397
 
 
398
        MAKE_ELEMENT_OR_LOSE(spider, decoder);
 
399
        gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->decoder);
 
400
 
 
401
        MAKE_ELEMENT_OR_LOSE(audioconvert, audioconvert);
 
402
        gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->audioconvert);
 
403
 
 
404
        MAKE_ELEMENT_OR_LOSE(audioscale, audioscale);
 
405
        gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->audioscale);
 
406
 
 
407
        MAKE_ELEMENT_OR_LOSE(wavenc, encoder);
 
408
        gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->encoder);
 
409
 
 
410
        /* Output sink */
 
411
 
 
412
        MAKE_ELEMENT_OR_LOSE(gnomevfssink, sink);
 
413
        if (recorder->priv->sink == NULL) {
 
414
                g_set_error (error,
 
415
                             RB_RECORDER_ERROR,
 
416
                             RB_RECORDER_ERROR_NO_AUDIO,
 
417
                             _("Could not create audio output element; check your settings"));
 
418
                gst_object_unref (GST_OBJECT (recorder->priv->pipeline));
 
419
                recorder->priv->pipeline = NULL;
 
420
                return;
 
421
        }
 
422
        gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->sink);
 
423
 
 
424
        gst_element_link_many (recorder->priv->src,
 
425
                               recorder->priv->typefind,
 
426
                               recorder->priv->decoder,
 
427
                               recorder->priv->audioconvert,
 
428
                               recorder->priv->audioscale,
 
429
                               NULL);
 
430
 
 
431
        filtercaps = gst_caps_new_simple ("audio/x-raw-int",
 
432
                                          "channels", G_TYPE_INT, 2,
 
433
                                          "rate",     G_TYPE_INT, 44100,
 
434
                                          "width",    G_TYPE_INT, 16,
 
435
                                          "depth",    G_TYPE_INT, 16,
 
436
                                          NULL);
 
437
        gst_element_link_filtered (recorder->priv->audioscale,
 
438
                                   recorder->priv->encoder,
 
439
                                   filtercaps);
 
440
        gst_caps_free (filtercaps);
 
441
 
 
442
        gst_element_link (recorder->priv->encoder,
 
443
                          recorder->priv->sink);
 
444
 
 
445
        recorder->priv->eos_signal_id =
 
446
                g_signal_connect_object (G_OBJECT (recorder->priv->pipeline), "eos",
 
447
                                         G_CALLBACK (eos_cb), recorder, 0);
 
448
 
 
449
        rb_debug ("Pipeline construction complete");
 
450
        return;
 
451
 
 
452
 missing_element:
 
453
        {
 
454
                g_set_error (error,
 
455
                             RB_RECORDER_ERROR,
 
456
                             RB_RECORDER_ERROR_GENERAL,
 
457
                             _("Failed to create %s element; check your installation"),
 
458
                             element_name);
 
459
                rb_recorder_gst_free_pipeline (recorder);
 
460
        }
 
461
}
 
462
 
 
463
static void
 
464
recorder_track_free (NautilusBurnRecorderTrack *track)
 
465
{
 
466
        if (track->contents.audio.filename) {
 
467
                char *lockfile = NULL;
 
468
                char *ext      = g_strrstr (track->contents.audio.filename, ".wav");
 
469
                if (ext)
 
470
                        lockfile = g_strndup (track->contents.audio.filename,
 
471
                                              ext - track->contents.audio.filename);
 
472
 
 
473
                if (g_file_test (track->contents.audio.filename, G_FILE_TEST_EXISTS)
 
474
                    && unlink (track->contents.audio.filename) != 0)
 
475
                        g_warning (_("Unable to unlink '%s'"), track->contents.audio.filename);
 
476
                if (lockfile) {
 
477
                        /* remove lockfile created by mkstemp */
 
478
                        if (unlink (lockfile) != 0)
 
479
                                g_warning (_("Unable to unlink '%s'"), lockfile);
 
480
                }
 
481
        }
 
482
 
 
483
        nautilus_burn_recorder_track_free (track);
 
484
}
 
485
 
 
486
static void
 
487
rb_recorder_finalize (GObject *object)
 
488
{
 
489
        RBRecorder *recorder = RB_RECORDER (object);
 
490
 
 
491
        rb_debug ("Finalize rb_recorder");
 
492
 
 
493
        rb_recorder_close (recorder, NULL);
 
494
 
 
495
        if (recorder->priv->recorder)
 
496
                nautilus_burn_recorder_cancel (recorder->priv->recorder, FALSE);
 
497
 
 
498
        g_list_foreach (recorder->priv->tracks,
 
499
                        (GFunc)recorder_track_free,
 
500
                        NULL);
 
501
        g_list_free (recorder->priv->tracks);
 
502
 
 
503
        g_free (recorder->priv);
 
504
 
 
505
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
506
}
 
507
 
 
508
RBRecorder *
 
509
rb_recorder_new (GError **error)
 
510
{
 
511
        RBRecorder *recorder;
 
512
        GstElement *dummy;
 
513
 
 
514
        rb_debug ("New rb_recorder");
 
515
 
 
516
        dummy = gst_element_factory_make ("fakesink", "fakesink");
 
517
        if (!dummy
 
518
            || !gst_scheduler_factory_make (NULL, GST_ELEMENT (dummy))) {
 
519
                g_set_error (error, RB_RECORDER_ERROR,
 
520
                             RB_RECORDER_ERROR_GENERAL,
 
521
                             _("Couldn't initialize scheduler.  Did you run gst-register?"));
 
522
                return NULL;
 
523
        }
 
524
 
 
525
        recorder = g_object_new (RB_TYPE_RECORDER, NULL, NULL);
 
526
 
 
527
        return recorder;
 
528
}
 
529
 
 
530
static gboolean
 
531
tick_timeout_cb (RBRecorder *recorder)
 
532
{
 
533
        gint64           position, total;
 
534
        double           fraction;
 
535
        double           rate;
 
536
        double           elapsed;
 
537
        double           secs;
 
538
        static GstFormat format = GST_FORMAT_BYTES;
 
539
 
 
540
        g_return_val_if_fail (recorder != NULL, FALSE);
 
541
        g_return_val_if_fail (RB_IS_RECORDER (recorder), FALSE);
 
542
        g_return_val_if_fail (recorder->priv != NULL, FALSE);
 
543
        g_return_val_if_fail (recorder->priv->pipeline != NULL, FALSE);
 
544
 
 
545
        if (gst_element_get_state (recorder->priv->pipeline) != GST_STATE_PLAYING) {
 
546
                recorder->priv->tick_timeout_id = 0;
 
547
                if (recorder->priv->start_timer) {
 
548
                        g_timer_destroy (recorder->priv->start_timer);
 
549
                        recorder->priv->start_timer = NULL;
 
550
                }
 
551
                return FALSE;
 
552
        }
 
553
 
 
554
        if (!gst_pad_query (recorder->priv->src_pad, GST_QUERY_POSITION, &format, &position)) {
 
555
                g_warning (_("Could not get current track position"));
 
556
                return TRUE;
 
557
        }
 
558
 
 
559
        if (!gst_pad_query (recorder->priv->src_pad, GST_QUERY_TOTAL, &format, &total)) {
 
560
                g_warning (_("Could not get current track position"));
 
561
                return TRUE;
 
562
        }
 
563
 
 
564
        if (! recorder->priv->start_timer) {
 
565
                recorder->priv->start_timer = g_timer_new ();
 
566
                recorder->priv->start_pos = position;
 
567
        }
 
568
 
 
569
        fraction = (float)position / (float)total;
 
570
 
 
571
        elapsed = g_timer_elapsed (recorder->priv->start_timer, NULL);
 
572
 
 
573
        rate = (double)(position - recorder->priv->start_pos) / elapsed;
 
574
 
 
575
        if (rate >= 1)
 
576
                secs = ceil ((total - position) / rate);
 
577
        else
 
578
                secs = -1;
 
579
 
 
580
        if (fraction != recorder->priv->progress) {
 
581
                recorder->priv->progress = fraction;
 
582
                g_signal_emit (G_OBJECT (recorder),
 
583
                               rb_recorder_signals [TRACK_PROGRESS_CHANGED],
 
584
                               0,
 
585
                               fraction, (long)secs);
 
586
        }
 
587
 
 
588
        /* Extra kick in the pants to keep things moving on a busy system */
 
589
        gst_bin_iterate (GST_BIN (recorder->priv->pipeline));
 
590
 
 
591
        return TRUE;
 
592
}
 
593
 
 
594
static gboolean
 
595
rb_recorder_sync_pipeline (RBRecorder *recorder,
 
596
                           GError    **error)
 
597
{
 
598
        g_return_val_if_fail (recorder != NULL, FALSE);
 
599
        g_return_val_if_fail (RB_IS_RECORDER (recorder), FALSE);
 
600
        g_return_val_if_fail (recorder->priv != NULL, FALSE);
 
601
        g_return_val_if_fail (recorder->priv->pipeline != NULL, FALSE);
 
602
        
 
603
        rb_debug ("Syncing pipeline");
 
604
        if (recorder->priv->playing) {
 
605
                rb_debug ("Playing pipeline");
 
606
                if (gst_element_set_state (recorder->priv->pipeline,
 
607
                                           GST_STATE_PLAYING) == GST_STATE_FAILURE) {
 
608
                        g_set_error (error,
 
609
                                     RB_RECORDER_ERROR,
 
610
                                     RB_RECORDER_ERROR_GENERAL,
 
611
                                     _("Could not start pipeline playing"));
 
612
                        return FALSE;
 
613
                }                               
 
614
                recorder->priv->idle_id = g_idle_add ((GSourceFunc)gst_bin_iterate,
 
615
                                                      GST_BIN (recorder->priv->pipeline));
 
616
                recorder->priv->tick_timeout_id = g_timeout_add (200,
 
617
                                                                 (GSourceFunc)tick_timeout_cb,
 
618
                                                                 recorder);
 
619
        } else {
 
620
                rb_debug ("Pausing pipeline");
 
621
                if (gst_element_set_state (recorder->priv->pipeline,
 
622
                                           GST_STATE_PAUSED) == GST_STATE_FAILURE) {
 
623
                        g_set_error (error,
 
624
                                     RB_RECORDER_ERROR,
 
625
                                     RB_RECORDER_ERROR_GENERAL,
 
626
                                     _("Could not pause playback"));
 
627
                        return FALSE;
 
628
                }
 
629
                if (recorder->priv->idle_id > 0) {
 
630
                        g_source_remove (recorder->priv->idle_id);
 
631
                        recorder->priv->idle_id = 0;
 
632
                }
 
633
                if (recorder->priv->tick_timeout_id > 0) {
 
634
                        g_source_remove (recorder->priv->tick_timeout_id);
 
635
                        recorder->priv->tick_timeout_id = 0;
 
636
                        if (recorder->priv->start_timer) {
 
637
                                g_timer_destroy (recorder->priv->start_timer);
 
638
                                recorder->priv->start_timer = NULL;
 
639
                        }
 
640
                }
 
641
        }
 
642
        return TRUE;
 
643
}
 
644
 
 
645
void
 
646
rb_recorder_close (RBRecorder *recorder,
 
647
                   GError    **error)
 
648
{
 
649
        g_return_if_fail (recorder != NULL);
 
650
        g_return_if_fail (RB_IS_RECORDER (recorder));
 
651
 
 
652
        rb_debug ("Closing rb_recorder");
 
653
 
 
654
        recorder->priv->playing = FALSE;
 
655
 
 
656
        g_free (recorder->priv->src_uri);
 
657
        recorder->priv->src_uri = NULL;
 
658
 
 
659
        g_free (recorder->priv->dest_file);
 
660
        recorder->priv->dest_file = NULL;
 
661
 
 
662
        if (recorder->priv->pipeline == NULL)
 
663
                return;
 
664
 
 
665
        rb_recorder_gst_free_pipeline (recorder);
 
666
}
 
667
 
 
668
void
 
669
rb_recorder_set_tmp_dir (RBRecorder   *recorder,
 
670
                         const char   *path,
 
671
                         GError      **error)
 
672
{
 
673
        g_return_if_fail (recorder != NULL);
 
674
        g_return_if_fail (RB_IS_RECORDER (recorder));
 
675
        g_return_if_fail (path != NULL);
 
676
 
 
677
        /* Check to make sure it exists and has enough space */
 
678
 
 
679
        g_free (recorder->priv->tmp_dir);
 
680
        recorder->priv->tmp_dir = g_strdup (path);
 
681
}
 
682
 
 
683
static char *
 
684
get_dest_from_uri (const char *tmp_dir,
 
685
                   const char *src_uri)
 
686
{
 
687
        char *lock_filename;
 
688
        char *filename;
 
689
        int   fd;
 
690
 
 
691
        lock_filename = g_build_filename (tmp_dir, "rb-burn-tmp.XXXXXX", NULL);
 
692
        fd = g_mkstemp (lock_filename);
 
693
        close (fd);
 
694
 
 
695
        /* keep empty file around until finalize
 
696
           it will serve as a lock file to protect our new filename */
 
697
 
 
698
        filename = g_strdup_printf ("%s.wav", lock_filename);
 
699
        g_free (lock_filename);
 
700
 
 
701
        return filename;
 
702
}
 
703
 
 
704
void
 
705
rb_recorder_open (RBRecorder   *recorder,
 
706
                  const char   *src_uri,
 
707
                  const char   *cdtext,
 
708
                  GError      **error)
 
709
{
 
710
        char    *dest_file;
 
711
        gboolean audiocd_mode = src_uri && g_str_has_prefix (src_uri, "audiocd://");
 
712
        
 
713
        g_return_if_fail (recorder != NULL);
 
714
        g_return_if_fail (RB_IS_RECORDER (recorder));
 
715
        g_return_if_fail (recorder->priv != NULL);
 
716
        g_return_if_fail (audiocd_mode != TRUE);
 
717
 
 
718
        rb_recorder_close (recorder, NULL);
 
719
 
 
720
        if (src_uri == NULL) {
 
721
                recorder->priv->playing = FALSE;
 
722
                return;
 
723
        }
 
724
 
 
725
        rb_recorder_construct (recorder, src_uri, error);
 
726
        if (error && *error)
 
727
                return;
 
728
                
 
729
        if (recorder->priv->idle_id > 0) {
 
730
                g_source_remove (recorder->priv->idle_id);
 
731
                recorder->priv->idle_id = 0;
 
732
        }
 
733
 
 
734
        g_object_set (G_OBJECT (recorder->priv->src), "iradio-mode", FALSE, NULL);
 
735
        gst_element_set_state (recorder->priv->src, GST_STATE_NULL);
 
736
        g_object_set (G_OBJECT (recorder->priv->src), "location", src_uri, NULL);
 
737
 
 
738
        g_free (recorder->priv->src_uri);
 
739
        recorder->priv->src_uri = g_strdup (src_uri);
 
740
 
 
741
        dest_file = get_dest_from_uri (recorder->priv->tmp_dir, src_uri);
 
742
        gst_element_set_state (recorder->priv->sink, GST_STATE_NULL);
 
743
        g_object_set (G_OBJECT (recorder->priv->sink), "location", dest_file, NULL);
 
744
        
 
745
        g_free (recorder->priv->dest_file);
 
746
        recorder->priv->dest_file = g_strdup (dest_file);
 
747
        g_free (dest_file);
 
748
 
 
749
        recorder->priv->playing = FALSE;
 
750
 
 
751
        add_track (recorder, cdtext);
 
752
 
 
753
        if (!rb_recorder_sync_pipeline (recorder, error)) {
 
754
                rb_recorder_close (recorder, NULL);
 
755
        }
 
756
}
 
757
 
 
758
void
 
759
rb_recorder_write (RBRecorder *recorder,
 
760
                   GError    **error)
 
761
{
 
762
        g_return_if_fail (recorder != NULL);
 
763
        g_return_if_fail (RB_IS_RECORDER (recorder));
 
764
        g_return_if_fail (recorder->priv != NULL);
 
765
 
 
766
        g_return_if_fail (recorder->priv->src_uri != NULL);
 
767
 
 
768
        recorder->priv->playing = TRUE;
 
769
 
 
770
        g_return_if_fail (recorder->priv->pipeline != NULL);
 
771
 
 
772
        g_signal_emit (recorder,
 
773
                       rb_recorder_signals [ACTION_CHANGED],
 
774
                       0,
 
775
                       RB_RECORDER_ACTION_FILE_CONVERTING);
 
776
 
 
777
        rb_recorder_sync_pipeline (recorder, error);
 
778
}
 
779
 
 
780
void
 
781
rb_recorder_pause (RBRecorder *recorder,
 
782
                   GError    **error)
 
783
{
 
784
        g_return_if_fail (recorder != NULL);
 
785
        g_return_if_fail (RB_IS_RECORDER (recorder));
 
786
        g_return_if_fail (recorder->priv != NULL);
 
787
 
 
788
        if (!recorder->priv->playing)
 
789
                return;
 
790
 
 
791
        recorder->priv->playing = FALSE;
 
792
 
 
793
        g_return_if_fail (recorder->priv->pipeline != NULL);
 
794
 
 
795
        rb_recorder_sync_pipeline (recorder, NULL);
 
796
}
 
797
 
 
798
char *
 
799
rb_recorder_get_device (RBRecorder  *recorder,
 
800
                        GError     **error)
 
801
{
 
802
        NautilusBurnDrive *drive;
 
803
 
 
804
        g_return_val_if_fail (recorder != NULL, NULL);
 
805
        g_return_val_if_fail (RB_IS_RECORDER (recorder), NULL);
 
806
 
 
807
        if (error)
 
808
                *error = NULL;
 
809
 
 
810
        drive = recorder->priv->drive;
 
811
 
 
812
        if (! drive) {
 
813
                g_set_error (error, RB_RECORDER_ERROR,
 
814
                             RB_RECORDER_ERROR_GENERAL,
 
815
                             _("Cannot find drive"));
 
816
                return NULL;
 
817
        }
 
818
 
 
819
        return g_strdup (drive->device);
 
820
}
 
821
 
 
822
gboolean
 
823
rb_recorder_set_device (RBRecorder  *recorder,
 
824
                        const char  *device,
 
825
                        GError     **error)
 
826
{
 
827
        GList *drives;
 
828
        GList *tmp;
 
829
 
 
830
        g_return_val_if_fail (recorder != NULL, FALSE);
 
831
        g_return_val_if_fail (RB_IS_RECORDER (recorder), FALSE);
 
832
        g_return_val_if_fail (device != NULL, FALSE);
 
833
 
 
834
        if (error)
 
835
                *error = NULL;
 
836
 
 
837
        drives = nautilus_burn_drive_get_list (TRUE, FALSE);
 
838
 
 
839
        for (tmp = drives; tmp != NULL; tmp = tmp->next) {
 
840
                NautilusBurnDrive *drive = (NautilusBurnDrive*) tmp->data;
 
841
                if (strcmp (drive->device, device) == 0) {
 
842
                        recorder->priv->drive = drive;
 
843
                        break;
 
844
                }
 
845
                nautilus_burn_drive_free (drive);
 
846
        }
 
847
        g_list_free (drives);
 
848
 
 
849
        if (! recorder->priv->drive) {
 
850
                g_set_error (error, RB_RECORDER_ERROR,
 
851
                             RB_RECORDER_ERROR_GENERAL,
 
852
                             _("Cannot find drive %s"),
 
853
                             device);
 
854
                return FALSE;
 
855
        }
 
856
 
 
857
        if (! (recorder->priv->drive->type & NAUTILUS_BURN_DRIVE_TYPE_CD_RECORDER)) {
 
858
                g_set_error (error, RB_RECORDER_ERROR,
 
859
                             RB_RECORDER_ERROR_GENERAL,
 
860
                             _("Drive %s is not a recorder"),
 
861
                             device);
 
862
                return FALSE;
 
863
        }
 
864
 
 
865
        return TRUE;
 
866
}
 
867
 
 
868
static void
 
869
rb_recorder_action_changed_cb (NautilusBurnRecorder        *cdrecorder,
 
870
                               NautilusBurnRecorderActions  cd_action,
 
871
                               NautilusBurnRecorderMedia    cd_media,
 
872
                               gpointer                     data)
 
873
{
 
874
        RBRecorder      *recorder = (RBRecorder*) data;
 
875
        RBRecorderAction action;
 
876
 
 
877
        switch (cd_action) {
 
878
        case NAUTILUS_BURN_RECORDER_ACTION_PREPARING_WRITE:
 
879
                action = RB_RECORDER_ACTION_DISC_PREPARING_WRITE;
 
880
                break;
 
881
        case NAUTILUS_BURN_RECORDER_ACTION_WRITING:
 
882
                action = RB_RECORDER_ACTION_DISC_WRITING;
 
883
                break;
 
884
        case NAUTILUS_BURN_RECORDER_ACTION_FIXATING:
 
885
                action = RB_RECORDER_ACTION_DISC_FIXATING;
 
886
                break;
 
887
        case NAUTILUS_BURN_RECORDER_ACTION_BLANKING:
 
888
                action = RB_RECORDER_ACTION_DISC_BLANKING;
 
889
                break;
 
890
        default:
 
891
                action = RB_RECORDER_ACTION_UNKNOWN;
 
892
        }
 
893
 
 
894
        g_signal_emit (recorder,
 
895
                       rb_recorder_signals [ACTION_CHANGED],
 
896
                       0,
 
897
                       action);
 
898
}
 
899
 
 
900
#ifdef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
 
901
/* If nautilus-cd-burner >= 2.12 */
 
902
static void
 
903
rb_recorder_burn_progress_cb (NautilusBurnRecorder *cdrecorder,
 
904
                              gdouble               fraction,
 
905
                              long                  secs,
 
906
                              gpointer              data)
 
907
{
 
908
        RBRecorder *recorder = (RBRecorder*) data;
 
909
 
 
910
        g_signal_emit (recorder,
 
911
                       rb_recorder_signals [BURN_PROGRESS_CHANGED],
 
912
                       0,
 
913
                       fraction,
 
914
                       secs);
 
915
}
 
916
#else
 
917
/* If nautilus-cd-burner == 2.10 */
 
918
static void
 
919
rb_recorder_burn_progress_cb (NautilusBurnRecorder *cdrecorder,
 
920
                              gdouble               fraction,
 
921
                              gpointer              data)
 
922
{
 
923
        RBRecorder *recorder = (RBRecorder*) data;
 
924
        long        secs     = -1;
 
925
 
 
926
        g_signal_emit (recorder,
 
927
                       rb_recorder_signals [BURN_PROGRESS_CHANGED],
 
928
                       0,
 
929
                       fraction,
 
930
                       secs);
 
931
}
 
932
#endif
 
933
 
 
934
static gboolean
 
935
rb_recorder_insert_cd_request_cb (NautilusBurnRecorder *cdrecorder,
 
936
                                  gboolean              is_reload,
 
937
                                  gboolean              can_rewrite,
 
938
                                  gboolean              busy_cd,
 
939
                                  gpointer              data)
 
940
{
 
941
        RBRecorder *recorder = (RBRecorder*) data;
 
942
        gboolean    res = FALSE;
 
943
 
 
944
        g_signal_emit (recorder,
 
945
                       rb_recorder_signals [INSERT_MEDIA_REQUEST],
 
946
                       0,
 
947
                       is_reload,
 
948
                       can_rewrite,
 
949
                       busy_cd,
 
950
                       &res);
 
951
 
 
952
        return res;
 
953
}
 
954
 
 
955
static int
 
956
rb_recorder_warn_data_loss_cb (NautilusBurnRecorder *cdrecorder,
 
957
                               RBRecorder           *recorder)
 
958
{
 
959
        int res = 0;
 
960
        int ret = 0;
 
961
        int retry_val;
 
962
        int cancel_val;
 
963
        int erase_val;
 
964
 
 
965
        g_signal_emit (G_OBJECT (recorder),
 
966
                       rb_recorder_signals [WARN_DATA_LOSS],
 
967
                       0, &res);
 
968
 
 
969
#ifdef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
 
970
        retry_val  = NAUTILUS_BURN_RECORDER_RESPONSE_RETRY;
 
971
        cancel_val = NAUTILUS_BURN_RECORDER_RESPONSE_CANCEL;
 
972
        erase_val  = NAUTILUS_BURN_RECORDER_RESPONSE_ERASE;
 
973
#else
 
974
        retry_val  = TRUE;
 
975
        cancel_val = TRUE;
 
976
        erase_val  = FALSE;
 
977
#endif
 
978
 
 
979
        switch (res) {
 
980
        case RB_RECORDER_RESPONSE_RETRY:
 
981
                ret = retry_val;
 
982
                break;
 
983
        case RB_RECORDER_RESPONSE_ERASE:
 
984
                ret = erase_val;
 
985
                break;
 
986
        case RB_RECORDER_RESPONSE_CANCEL:
 
987
        default:
 
988
                ret = cancel_val;
 
989
                break;
 
990
        }
 
991
 
 
992
        return ret;
 
993
}
 
994
 
 
995
static NautilusBurnDrive *
 
996
rb_recorder_get_default_drive (void)
 
997
{
 
998
        NautilusBurnDrive *drive  = NULL;
 
999
        GList             *drives = NULL;
 
1000
 
 
1001
        drives = nautilus_burn_drive_get_list (TRUE, FALSE);
 
1002
 
 
1003
        if (drives)
 
1004
                drive = nautilus_burn_drive_copy ((NautilusBurnDrive*) drives->data);
 
1005
 
 
1006
        g_list_foreach (drives, (GFunc)nautilus_burn_drive_free, NULL);
 
1007
        g_list_free (drives);
 
1008
 
 
1009
        return drive;
 
1010
}
 
1011
 
 
1012
char *
 
1013
rb_recorder_get_default_device (void)
 
1014
{
 
1015
        NautilusBurnDrive *drive;
 
1016
        char              *device = NULL;
 
1017
 
 
1018
        drive = rb_recorder_get_default_drive ();
 
1019
 
 
1020
        if (drive) {
 
1021
                device = g_strdup (drive->device);
 
1022
                nautilus_burn_drive_free (drive);
 
1023
        }
 
1024
 
 
1025
        return device;
 
1026
}
 
1027
 
 
1028
gint64
 
1029
rb_recorder_get_media_length (RBRecorder *recorder,
 
1030
                              GError    **error)
 
1031
{
 
1032
        char  *device;
 
1033
        gint64 size;
 
1034
        gint64 secs;
 
1035
 
 
1036
        g_return_val_if_fail (recorder != NULL, FALSE);
 
1037
        g_return_val_if_fail (RB_IS_RECORDER (recorder), FALSE);
 
1038
        g_return_val_if_fail (recorder->priv != NULL, FALSE);
 
1039
 
 
1040
        if (recorder->priv->drive)
 
1041
                device = g_strdup (recorder->priv->drive->device);
 
1042
        else
 
1043
                device = rb_recorder_get_default_device ();
 
1044
                
 
1045
        size = nautilus_burn_drive_get_media_size_from_path (device);
 
1046
        if (size > 0) {
 
1047
#ifdef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
 
1048
                secs = NAUTILUS_BURN_DRIVE_SIZE_TO_TIME (size);
 
1049
#else
 
1050
                secs = SIZE_TO_TIME (size);
 
1051
#endif
 
1052
        } else {
 
1053
                secs = size;
 
1054
        }
 
1055
 
 
1056
        g_free (device);
 
1057
 
 
1058
        return secs;
 
1059
}
 
1060
 
 
1061
/* Copyright (C) Bastien Nocera */
 
1062
/* From xine-lib, whoop */
 
1063
typedef struct __attribute__((__packed__)) {
 
1064
        gint16   wFormatTag;
 
1065
        gint16   nChannels;
 
1066
        gint32   nSamplesPerSec;
 
1067
        gint32   nAvgBytesPerSec;
 
1068
        gint16   nBlockAlign;
 
1069
        gint16   wBitsPerSample;
 
1070
        gint16   cbSize;
 
1071
} waveformat;
 
1072
#ifndef ATTRIBUTE_PACKED
 
1073
#pragma pack()
 
1074
#endif
 
1075
 
 
1076
#define ACB_ERROR_OPEN                          -1
 
1077
#define ACB_ERROR_NOT_WAVE_TOO_SMALL            -2
 
1078
#define ACB_ERROR_NOT_WAVE_FILE                 -3
 
1079
#define ACB_ERROR_NOT_WAVE_FORMAT               -4
 
1080
 
 
1081
/* Copyright (C) Bastien Nocera */
 
1082
/* Data from
 
1083
 * http://www.onicos.com/staff/iz/formats/wav.html
 
1084
 */
 
1085
static gint64
 
1086
acb_wave_time (const char *filename)
 
1087
{
 
1088
#define WAV_SIGNATURE_SIZE 16
 
1089
#define LPCM_BITRATE (16 * 44100 * 2)
 
1090
        char        buffer [WAV_SIGNATURE_SIZE];
 
1091
        int         fd, len;
 
1092
        waveformat *wav;
 
1093
 
 
1094
        fd = open (filename, 0);
 
1095
        if (fd < 0)
 
1096
                return ACB_ERROR_OPEN;
 
1097
 
 
1098
        if (read (fd, buffer, WAV_SIGNATURE_SIZE) != WAV_SIGNATURE_SIZE)
 
1099
                return ACB_ERROR_NOT_WAVE_TOO_SMALL;
 
1100
 
 
1101
        if ((buffer [0] != 'R') ||
 
1102
            (buffer [1] != 'I') ||
 
1103
            (buffer [2] != 'F') ||
 
1104
            (buffer [3] != 'F') ||
 
1105
            (buffer [8] != 'W') ||
 
1106
            (buffer [9] != 'A') ||
 
1107
            (buffer [10] != 'V') ||
 
1108
            (buffer [11] != 'E') ||
 
1109
            (buffer [12] != 'f') ||
 
1110
            (buffer [13] != 'm') ||
 
1111
            (buffer [14] != 't') ||
 
1112
            (buffer [15] != ' '))
 
1113
                return ACB_ERROR_NOT_WAVE_FORMAT;
 
1114
 
 
1115
        if (read (fd, &len, sizeof(len)) != sizeof (len)) {
 
1116
                close (fd);
 
1117
                return ACB_ERROR_NOT_WAVE_TOO_SMALL;
 
1118
        }
 
1119
 
 
1120
        if (GINT_FROM_LE (len) != 16) {
 
1121
                close (fd);
 
1122
                g_print ("file len not defined\n");
 
1123
                return ACB_ERROR_NOT_WAVE_FORMAT;
 
1124
        }
 
1125
 
 
1126
        wav = g_malloc (len);
 
1127
        if (read (fd, wav, len) != len) {
 
1128
                g_free (wav);
 
1129
                close (fd);
 
1130
                return ACB_ERROR_NOT_WAVE_FILE;
 
1131
        }
 
1132
 
 
1133
        close (fd);
 
1134
 
 
1135
        if (wav->nChannels != 2
 
1136
            || wav->nSamplesPerSec != 44100
 
1137
            || wav->wBitsPerSample != 16) {
 
1138
                g_free (wav);
 
1139
                return ACB_ERROR_NOT_WAVE_FORMAT;
 
1140
        }
 
1141
 
 
1142
        g_free (wav);
 
1143
 
 
1144
        {
 
1145
                struct stat buf;
 
1146
 
 
1147
                if (stat (filename, &buf) != 0)
 
1148
                        return ACB_ERROR_OPEN;
 
1149
 
 
1150
                return buf.st_size * 8 / LPCM_BITRATE;
 
1151
        }
 
1152
}
 
1153
 
 
1154
static gint64
 
1155
get_tracks_length (RBRecorder *recorder,
 
1156
                   GError    **error)
 
1157
{
 
1158
        GList *l;
 
1159
        gint64 total = 0;
 
1160
 
 
1161
        if (!recorder->priv->tracks)
 
1162
                return -1;
 
1163
 
 
1164
        for (l = recorder->priv->tracks; l; l = l->next) {
 
1165
                NautilusBurnRecorderTrack *track = l->data;
 
1166
                gint64                     length;
 
1167
 
 
1168
                length = acb_wave_time (track->contents.audio.filename);
 
1169
                if (length < 0) {
 
1170
                        g_warning (_("Could not get track time for file: %s"),
 
1171
                                   track->contents.audio.filename);
 
1172
                        return -1;
 
1173
                }
 
1174
                total += length;
 
1175
        }
 
1176
 
 
1177
        return total;
 
1178
}
 
1179
 
 
1180
int
 
1181
rb_recorder_burn_cancel (RBRecorder *recorder)
 
1182
{
 
1183
 
 
1184
        g_return_val_if_fail (recorder != NULL, RB_RECORDER_RESULT_ERROR);
 
1185
        g_return_val_if_fail (RB_IS_RECORDER (recorder), RB_RECORDER_RESULT_ERROR);
 
1186
        g_return_val_if_fail (recorder->priv != NULL, RB_RECORDER_RESULT_ERROR);
 
1187
 
 
1188
        g_return_val_if_fail (recorder->priv->recorder != NULL, RB_RECORDER_RESULT_ERROR);
 
1189
 
 
1190
        nautilus_burn_recorder_cancel (recorder->priv->recorder, FALSE);
 
1191
 
 
1192
        return RB_RECORDER_RESULT_FINISHED;
 
1193
}
 
1194
 
 
1195
int
 
1196
rb_recorder_burn (RBRecorder *recorder,
 
1197
                  int         speed,
 
1198
                  GError    **error)
 
1199
{
 
1200
        NautilusBurnRecorder          *cdrecorder;
 
1201
        NautilusBurnRecorderWriteFlags flags;
 
1202
        GError                        *local_error = NULL;
 
1203
        int                            res;
 
1204
        gboolean                       result;
 
1205
        gint64                         tracks_length;
 
1206
        gint64                         media_length;
 
1207
 
 
1208
        g_return_val_if_fail (recorder != NULL, RB_RECORDER_RESULT_ERROR);
 
1209
        g_return_val_if_fail (RB_IS_RECORDER (recorder), RB_RECORDER_RESULT_ERROR);
 
1210
        g_return_val_if_fail (recorder->priv != NULL, RB_RECORDER_RESULT_ERROR);
 
1211
 
 
1212
        g_return_val_if_fail (recorder->priv->recorder == NULL, RB_RECORDER_RESULT_ERROR);
 
1213
 
 
1214
        if (!recorder->priv->tracks)
 
1215
                return RB_RECORDER_RESULT_ERROR;
 
1216
 
 
1217
        if (!recorder->priv->drive) {
 
1218
                char *default_device = rb_recorder_get_default_device ();
 
1219
 
 
1220
                if (!default_device) {
 
1221
                        g_warning (_("Could not determine default writer device"));
 
1222
                        return RB_RECORDER_RESULT_ERROR;
 
1223
                }
 
1224
 
 
1225
                rb_recorder_set_device  (recorder, default_device, error);
 
1226
                g_free (default_device);
 
1227
                if (error && *error)
 
1228
                        return RB_RECORDER_RESULT_ERROR;
 
1229
        }
 
1230
 
 
1231
        tracks_length = get_tracks_length (recorder, error);
 
1232
        if (tracks_length <= 0) {
 
1233
                g_set_error (error,
 
1234
                             RB_RECORDER_ERROR,
 
1235
                             RB_RECORDER_ERROR_INTERNAL,
 
1236
                             _("Could not determine audio track durations."));
 
1237
                return RB_RECORDER_RESULT_ERROR;
 
1238
        }
 
1239
 
 
1240
        media_length = rb_recorder_get_media_length (recorder, error);
 
1241
 
 
1242
        /* don't fail here if media length cannot be determined
 
1243
         * nautilus_burn_recorder_write_tracks will fail and issue a signal */
 
1244
        if ((media_length > 0) && (tracks_length > media_length)) {
 
1245
                char *duration_string = g_strdup_printf ("%" G_GINT64_FORMAT, tracks_length / 60);
 
1246
                char *media_duration_string = g_strdup_printf ("%" G_GINT64_FORMAT, media_length / 60);
 
1247
 
 
1248
                g_set_error (error,
 
1249
                             RB_RECORDER_ERROR,
 
1250
                             RB_RECORDER_ERROR_GENERAL,
 
1251
                             _("This playlist is %s minutes long.  "
 
1252
                               "This exceeds the %s minute length of the media in the drive."),
 
1253
                             duration_string,
 
1254
                             media_duration_string);
 
1255
 
 
1256
                g_free (duration_string);
 
1257
                g_free (media_duration_string);
 
1258
 
 
1259
                return RB_RECORDER_RESULT_ERROR;
 
1260
        }
 
1261
 
 
1262
        cdrecorder = nautilus_burn_recorder_new ();
 
1263
        recorder->priv->recorder = cdrecorder;
 
1264
 
 
1265
        g_signal_connect_object (G_OBJECT (cdrecorder), "progress-changed",
 
1266
                                 G_CALLBACK (rb_recorder_burn_progress_cb), recorder, 0);
 
1267
        g_signal_connect_object (G_OBJECT (cdrecorder), "action-changed",
 
1268
                                 G_CALLBACK (rb_recorder_action_changed_cb), recorder, 0);
 
1269
        g_signal_connect_object (G_OBJECT (cdrecorder), "insert-media-request",
 
1270
                                 G_CALLBACK (rb_recorder_insert_cd_request_cb), recorder, 0);
 
1271
        g_signal_connect_object (G_OBJECT (cdrecorder), "warn-data-loss",
 
1272
                                 G_CALLBACK (rb_recorder_warn_data_loss_cb), recorder, 0);
 
1273
 
 
1274
        flags = 0;
 
1275
        if (FALSE)
 
1276
                flags |= NAUTILUS_BURN_RECORDER_WRITE_DUMMY_WRITE;
 
1277
        if (TRUE)
 
1278
                flags |= NAUTILUS_BURN_RECORDER_WRITE_DEBUG;
 
1279
        if (TRUE)
 
1280
                flags |= NAUTILUS_BURN_RECORDER_WRITE_DISC_AT_ONCE;
 
1281
 
 
1282
#ifdef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
 
1283
        /* If nautilus-cd-burner >= 2.12 */
 
1284
        res = nautilus_burn_recorder_write_tracks (cdrecorder,
 
1285
                                                   recorder->priv->drive,
 
1286
                                                   recorder->priv->tracks,
 
1287
                                                   speed,
 
1288
                                                   flags,
 
1289
                                                   &local_error);
 
1290
#else
 
1291
        /* If nautilus-cd-burner == 2.10 */
 
1292
        res = nautilus_burn_recorder_write_tracks (cdrecorder,
 
1293
                                                   recorder->priv->drive,
 
1294
                                                   recorder->priv->tracks,
 
1295
                                                   speed,
 
1296
                                                   flags);
 
1297
#endif
 
1298
 
 
1299
        if (res == NAUTILUS_BURN_RECORDER_RESULT_FINISHED) {
 
1300
                result = RB_RECORDER_RESULT_FINISHED;
 
1301
        } else if (res == NAUTILUS_BURN_RECORDER_RESULT_ERROR) {
 
1302
                char *msg;
 
1303
 
 
1304
 
 
1305
                if (local_error) {
 
1306
                        msg = g_strdup_printf (_("There was an error writing to the CD:\n%s"),
 
1307
                                               local_error->message);
 
1308
                        g_error_free (local_error);
 
1309
                } else {
 
1310
                        msg = g_strdup (_("There was an error writing to the CD"));
 
1311
                }
 
1312
 
 
1313
                g_set_error (error,
 
1314
                             RB_RECORDER_ERROR,
 
1315
                             RB_RECORDER_ERROR_GENERAL,
 
1316
                             msg);
 
1317
                g_free (msg);
 
1318
                result = RB_RECORDER_RESULT_ERROR;
 
1319
        } else {
 
1320
                /* cancelled */
 
1321
                result = RB_RECORDER_RESULT_CANCEL;
 
1322
        }
 
1323
        
 
1324
        g_object_unref (cdrecorder);
 
1325
        recorder->priv->recorder = NULL;
 
1326
 
 
1327
        return result;
 
1328
}