1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
3
* arch-tag: Implementation of GStreamer recorder backend
5
* Copyright (C) 2004-2005 William Jon McCann <mccann@jhu.edu>
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.
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.
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.
29
#include <sys/types.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>
40
#include "rb-recorder.h"
41
#include "rb-recorder-marshal.h"
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);
49
struct _RBRecorderPrivate {
60
GstElement *audioconvert;
61
GstElement *audioscale;
66
guint error_signal_id;
68
guint tick_timeout_id;
77
NautilusBurnDrive *drive;
78
NautilusBurnRecorder *recorder;
88
TRACK_PROGRESS_CHANGED,
89
BURN_PROGRESS_CHANGED,
94
} RBRecorderSignalType;
102
static guint rb_recorder_signals [LAST_SIGNAL] = { 0 };
104
static GObjectClass *parent_class = NULL;
107
rb_recorder_enabled (void)
109
char *device = rb_recorder_get_default_device ();
110
gboolean enabled = (device != NULL);
118
rb_recorder_error_quark (void)
120
static GQuark quark = 0;
122
quark = g_quark_from_static_string ("rb_recorder_error");
127
G_DEFINE_TYPE(RBRecorder, rb_recorder, G_TYPE_OBJECT)
130
rb_recorder_class_init (RBRecorderClass *klass)
132
GObjectClass *object_class;
134
parent_class = g_type_class_peek_parent (klass);
135
object_class = (GObjectClass *) klass;
137
object_class->finalize = rb_recorder_finalize;
139
rb_recorder_signals [EOS] =
141
G_TYPE_FROM_CLASS (klass),
145
g_cclosure_marshal_VOID__VOID,
148
rb_recorder_signals [TRACK_PROGRESS_CHANGED] =
149
g_signal_new ("track-progress-changed",
150
G_TYPE_FROM_CLASS (klass),
154
rb_recorder_marshal_VOID__DOUBLE_LONG,
159
rb_recorder_signals [BURN_PROGRESS_CHANGED] =
160
g_signal_new ("burn-progress-changed",
161
G_TYPE_FROM_CLASS (klass),
165
rb_recorder_marshal_VOID__DOUBLE_LONG,
170
rb_recorder_signals [ACTION_CHANGED] =
171
g_signal_new ("action-changed",
172
G_TYPE_FROM_CLASS (klass),
176
g_cclosure_marshal_VOID__INT,
180
rb_recorder_signals [INSERT_MEDIA_REQUEST] =
181
g_signal_new ("insert-media-request",
182
G_TYPE_FROM_CLASS (klass),
186
rb_recorder_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
192
rb_recorder_signals [WARN_DATA_LOSS] =
193
g_signal_new ("warn-data-loss",
194
G_TYPE_FROM_CLASS (klass),
198
rb_recorder_marshal_INT__VOID,
200
rb_recorder_signals [ERROR] =
201
g_signal_new ("error",
202
G_TYPE_FROM_CLASS (klass),
206
g_cclosure_marshal_VOID__POINTER,
213
rb_recorder_init (RBRecorder *recorder)
215
recorder->priv = g_new0 (RBRecorderPrivate, 1);
217
recorder->priv->tmp_dir = g_strdup (g_get_tmp_dir ());
221
rb_recorder_gst_free_pipeline (RBRecorder *recorder)
223
rb_debug ("Freeing rb_recorder pipeline");
225
if (recorder->priv->pipeline == NULL)
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;
237
if (recorder->priv->idle_id > 0) {
238
g_source_remove (recorder->priv->idle_id);
239
recorder->priv->idle_id = 0;
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;
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;
258
gst_object_unref (GST_OBJECT (recorder->priv->pipeline));
259
recorder->priv->pipeline = NULL;
263
add_track (RBRecorder *recorder,
266
NautilusBurnRecorderTrack *track;
269
g_return_val_if_fail (RB_IS_RECORDER (recorder), FALSE);
271
filename = g_strdup (recorder->priv->dest_file);
273
track = g_new0 (NautilusBurnRecorderTrack, 1);
275
track->type = NAUTILUS_BURN_RECORDER_TRACK_TYPE_AUDIO;
276
track->contents.audio.filename = filename;
278
track->contents.audio.cdtext = g_strdup (cdtext);
280
recorder->priv->tracks = g_list_append (recorder->priv->tracks, track);
286
eos_cb (GstElement *element,
287
RBRecorder *recorder)
291
if (recorder->priv->pipeline)
292
gst_element_set_state (recorder->priv->pipeline, GST_STATE_NULL);
294
g_signal_emit (G_OBJECT (recorder), rb_recorder_signals [EOS], 0);
298
error_signal_idle (RBRecorderSignal *signal)
300
g_signal_emit (G_OBJECT (signal->object),
301
rb_recorder_signals [ERROR],
305
/* close if not already closing */
306
if (signal->object->priv->src_uri != NULL)
307
rb_recorder_close (signal->object, NULL);
309
g_object_unref (signal->object);
310
g_error_free (signal->error);
317
rb_recorder_gst_signal_error (RBRecorder *recorder,
320
RBRecorderSignal *signal;
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,
327
g_object_ref (recorder);
329
g_idle_add ((GSourceFunc)error_signal_idle, signal);
333
error_cb (GstElement *element,
337
RBRecorder *recorder)
341
rb_recorder_gst_signal_error (recorder, error->message);
345
rb_recorder_construct (RBRecorder *recorder,
349
char *element_name = NULL;
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; \
360
rb_recorder_gst_free_pipeline (recorder);
362
/* The recording pipeline looks like:
363
* { src ! spider ! audioconvert ! audioscale
364
* ! audio/x-raw-int,rate=44100,width=16,depth=16 ! wavenc ! sink }
367
recorder->priv->pipeline = gst_pipeline_new ("pipeline");
368
if (!recorder->priv->pipeline) {
371
RB_RECORDER_ERROR_GENERAL,
372
_("Failed to create pipeline"));
373
rb_recorder_gst_free_pipeline (recorder);
377
recorder->priv->error_signal_id =
378
g_signal_connect_object (G_OBJECT (recorder->priv->pipeline),
380
G_CALLBACK (error_cb),
383
/* Construct elements */
387
MAKE_ELEMENT_OR_LOSE(gnomevfssrc, src);
388
gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->src);
390
recorder->priv->src_pad = gst_element_get_pad (recorder->priv->src, "src");
391
g_assert (recorder->priv->src_pad); /* TODO: GError */
395
MAKE_ELEMENT_OR_LOSE(typefind, typefind);
396
gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->typefind);
398
MAKE_ELEMENT_OR_LOSE(spider, decoder);
399
gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->decoder);
401
MAKE_ELEMENT_OR_LOSE(audioconvert, audioconvert);
402
gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->audioconvert);
404
MAKE_ELEMENT_OR_LOSE(audioscale, audioscale);
405
gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->audioscale);
407
MAKE_ELEMENT_OR_LOSE(wavenc, encoder);
408
gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->encoder);
412
MAKE_ELEMENT_OR_LOSE(gnomevfssink, sink);
413
if (recorder->priv->sink == NULL) {
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;
422
gst_bin_add (GST_BIN (recorder->priv->pipeline), recorder->priv->sink);
424
gst_element_link_many (recorder->priv->src,
425
recorder->priv->typefind,
426
recorder->priv->decoder,
427
recorder->priv->audioconvert,
428
recorder->priv->audioscale,
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,
437
gst_element_link_filtered (recorder->priv->audioscale,
438
recorder->priv->encoder,
440
gst_caps_free (filtercaps);
442
gst_element_link (recorder->priv->encoder,
443
recorder->priv->sink);
445
recorder->priv->eos_signal_id =
446
g_signal_connect_object (G_OBJECT (recorder->priv->pipeline), "eos",
447
G_CALLBACK (eos_cb), recorder, 0);
449
rb_debug ("Pipeline construction complete");
456
RB_RECORDER_ERROR_GENERAL,
457
_("Failed to create %s element; check your installation"),
459
rb_recorder_gst_free_pipeline (recorder);
464
recorder_track_free (NautilusBurnRecorderTrack *track)
466
if (track->contents.audio.filename) {
467
char *lockfile = NULL;
468
char *ext = g_strrstr (track->contents.audio.filename, ".wav");
470
lockfile = g_strndup (track->contents.audio.filename,
471
ext - track->contents.audio.filename);
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);
477
/* remove lockfile created by mkstemp */
478
if (unlink (lockfile) != 0)
479
g_warning (_("Unable to unlink '%s'"), lockfile);
483
nautilus_burn_recorder_track_free (track);
487
rb_recorder_finalize (GObject *object)
489
RBRecorder *recorder = RB_RECORDER (object);
491
rb_debug ("Finalize rb_recorder");
493
rb_recorder_close (recorder, NULL);
495
if (recorder->priv->recorder)
496
nautilus_burn_recorder_cancel (recorder->priv->recorder, FALSE);
498
g_list_foreach (recorder->priv->tracks,
499
(GFunc)recorder_track_free,
501
g_list_free (recorder->priv->tracks);
503
g_free (recorder->priv);
505
G_OBJECT_CLASS (parent_class)->finalize (object);
509
rb_recorder_new (GError **error)
511
RBRecorder *recorder;
514
rb_debug ("New rb_recorder");
516
dummy = gst_element_factory_make ("fakesink", "fakesink");
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?"));
525
recorder = g_object_new (RB_TYPE_RECORDER, NULL, NULL);
531
tick_timeout_cb (RBRecorder *recorder)
533
gint64 position, total;
538
static GstFormat format = GST_FORMAT_BYTES;
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);
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;
554
if (!gst_pad_query (recorder->priv->src_pad, GST_QUERY_POSITION, &format, &position)) {
555
g_warning (_("Could not get current track position"));
559
if (!gst_pad_query (recorder->priv->src_pad, GST_QUERY_TOTAL, &format, &total)) {
560
g_warning (_("Could not get current track position"));
564
if (! recorder->priv->start_timer) {
565
recorder->priv->start_timer = g_timer_new ();
566
recorder->priv->start_pos = position;
569
fraction = (float)position / (float)total;
571
elapsed = g_timer_elapsed (recorder->priv->start_timer, NULL);
573
rate = (double)(position - recorder->priv->start_pos) / elapsed;
576
secs = ceil ((total - position) / rate);
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],
585
fraction, (long)secs);
588
/* Extra kick in the pants to keep things moving on a busy system */
589
gst_bin_iterate (GST_BIN (recorder->priv->pipeline));
595
rb_recorder_sync_pipeline (RBRecorder *recorder,
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);
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) {
610
RB_RECORDER_ERROR_GENERAL,
611
_("Could not start pipeline playing"));
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,
620
rb_debug ("Pausing pipeline");
621
if (gst_element_set_state (recorder->priv->pipeline,
622
GST_STATE_PAUSED) == GST_STATE_FAILURE) {
625
RB_RECORDER_ERROR_GENERAL,
626
_("Could not pause playback"));
629
if (recorder->priv->idle_id > 0) {
630
g_source_remove (recorder->priv->idle_id);
631
recorder->priv->idle_id = 0;
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;
646
rb_recorder_close (RBRecorder *recorder,
649
g_return_if_fail (recorder != NULL);
650
g_return_if_fail (RB_IS_RECORDER (recorder));
652
rb_debug ("Closing rb_recorder");
654
recorder->priv->playing = FALSE;
656
g_free (recorder->priv->src_uri);
657
recorder->priv->src_uri = NULL;
659
g_free (recorder->priv->dest_file);
660
recorder->priv->dest_file = NULL;
662
if (recorder->priv->pipeline == NULL)
665
rb_recorder_gst_free_pipeline (recorder);
669
rb_recorder_set_tmp_dir (RBRecorder *recorder,
673
g_return_if_fail (recorder != NULL);
674
g_return_if_fail (RB_IS_RECORDER (recorder));
675
g_return_if_fail (path != NULL);
677
/* Check to make sure it exists and has enough space */
679
g_free (recorder->priv->tmp_dir);
680
recorder->priv->tmp_dir = g_strdup (path);
684
get_dest_from_uri (const char *tmp_dir,
691
lock_filename = g_build_filename (tmp_dir, "rb-burn-tmp.XXXXXX", NULL);
692
fd = g_mkstemp (lock_filename);
695
/* keep empty file around until finalize
696
it will serve as a lock file to protect our new filename */
698
filename = g_strdup_printf ("%s.wav", lock_filename);
699
g_free (lock_filename);
705
rb_recorder_open (RBRecorder *recorder,
711
gboolean audiocd_mode = src_uri && g_str_has_prefix (src_uri, "audiocd://");
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);
718
rb_recorder_close (recorder, NULL);
720
if (src_uri == NULL) {
721
recorder->priv->playing = FALSE;
725
rb_recorder_construct (recorder, src_uri, error);
729
if (recorder->priv->idle_id > 0) {
730
g_source_remove (recorder->priv->idle_id);
731
recorder->priv->idle_id = 0;
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);
738
g_free (recorder->priv->src_uri);
739
recorder->priv->src_uri = g_strdup (src_uri);
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);
745
g_free (recorder->priv->dest_file);
746
recorder->priv->dest_file = g_strdup (dest_file);
749
recorder->priv->playing = FALSE;
751
add_track (recorder, cdtext);
753
if (!rb_recorder_sync_pipeline (recorder, error)) {
754
rb_recorder_close (recorder, NULL);
759
rb_recorder_write (RBRecorder *recorder,
762
g_return_if_fail (recorder != NULL);
763
g_return_if_fail (RB_IS_RECORDER (recorder));
764
g_return_if_fail (recorder->priv != NULL);
766
g_return_if_fail (recorder->priv->src_uri != NULL);
768
recorder->priv->playing = TRUE;
770
g_return_if_fail (recorder->priv->pipeline != NULL);
772
g_signal_emit (recorder,
773
rb_recorder_signals [ACTION_CHANGED],
775
RB_RECORDER_ACTION_FILE_CONVERTING);
777
rb_recorder_sync_pipeline (recorder, error);
781
rb_recorder_pause (RBRecorder *recorder,
784
g_return_if_fail (recorder != NULL);
785
g_return_if_fail (RB_IS_RECORDER (recorder));
786
g_return_if_fail (recorder->priv != NULL);
788
if (!recorder->priv->playing)
791
recorder->priv->playing = FALSE;
793
g_return_if_fail (recorder->priv->pipeline != NULL);
795
rb_recorder_sync_pipeline (recorder, NULL);
799
rb_recorder_get_device (RBRecorder *recorder,
802
NautilusBurnDrive *drive;
804
g_return_val_if_fail (recorder != NULL, NULL);
805
g_return_val_if_fail (RB_IS_RECORDER (recorder), NULL);
810
drive = recorder->priv->drive;
813
g_set_error (error, RB_RECORDER_ERROR,
814
RB_RECORDER_ERROR_GENERAL,
815
_("Cannot find drive"));
819
return g_strdup (drive->device);
823
rb_recorder_set_device (RBRecorder *recorder,
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);
837
drives = nautilus_burn_drive_get_list (TRUE, FALSE);
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;
845
nautilus_burn_drive_free (drive);
847
g_list_free (drives);
849
if (! recorder->priv->drive) {
850
g_set_error (error, RB_RECORDER_ERROR,
851
RB_RECORDER_ERROR_GENERAL,
852
_("Cannot find drive %s"),
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"),
869
rb_recorder_action_changed_cb (NautilusBurnRecorder *cdrecorder,
870
NautilusBurnRecorderActions cd_action,
871
NautilusBurnRecorderMedia cd_media,
874
RBRecorder *recorder = (RBRecorder*) data;
875
RBRecorderAction action;
878
case NAUTILUS_BURN_RECORDER_ACTION_PREPARING_WRITE:
879
action = RB_RECORDER_ACTION_DISC_PREPARING_WRITE;
881
case NAUTILUS_BURN_RECORDER_ACTION_WRITING:
882
action = RB_RECORDER_ACTION_DISC_WRITING;
884
case NAUTILUS_BURN_RECORDER_ACTION_FIXATING:
885
action = RB_RECORDER_ACTION_DISC_FIXATING;
887
case NAUTILUS_BURN_RECORDER_ACTION_BLANKING:
888
action = RB_RECORDER_ACTION_DISC_BLANKING;
891
action = RB_RECORDER_ACTION_UNKNOWN;
894
g_signal_emit (recorder,
895
rb_recorder_signals [ACTION_CHANGED],
900
#ifdef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
901
/* If nautilus-cd-burner >= 2.12 */
903
rb_recorder_burn_progress_cb (NautilusBurnRecorder *cdrecorder,
908
RBRecorder *recorder = (RBRecorder*) data;
910
g_signal_emit (recorder,
911
rb_recorder_signals [BURN_PROGRESS_CHANGED],
917
/* If nautilus-cd-burner == 2.10 */
919
rb_recorder_burn_progress_cb (NautilusBurnRecorder *cdrecorder,
923
RBRecorder *recorder = (RBRecorder*) data;
926
g_signal_emit (recorder,
927
rb_recorder_signals [BURN_PROGRESS_CHANGED],
935
rb_recorder_insert_cd_request_cb (NautilusBurnRecorder *cdrecorder,
937
gboolean can_rewrite,
941
RBRecorder *recorder = (RBRecorder*) data;
942
gboolean res = FALSE;
944
g_signal_emit (recorder,
945
rb_recorder_signals [INSERT_MEDIA_REQUEST],
956
rb_recorder_warn_data_loss_cb (NautilusBurnRecorder *cdrecorder,
957
RBRecorder *recorder)
965
g_signal_emit (G_OBJECT (recorder),
966
rb_recorder_signals [WARN_DATA_LOSS],
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;
980
case RB_RECORDER_RESPONSE_RETRY:
983
case RB_RECORDER_RESPONSE_ERASE:
986
case RB_RECORDER_RESPONSE_CANCEL:
995
static NautilusBurnDrive *
996
rb_recorder_get_default_drive (void)
998
NautilusBurnDrive *drive = NULL;
999
GList *drives = NULL;
1001
drives = nautilus_burn_drive_get_list (TRUE, FALSE);
1004
drive = nautilus_burn_drive_copy ((NautilusBurnDrive*) drives->data);
1006
g_list_foreach (drives, (GFunc)nautilus_burn_drive_free, NULL);
1007
g_list_free (drives);
1013
rb_recorder_get_default_device (void)
1015
NautilusBurnDrive *drive;
1016
char *device = NULL;
1018
drive = rb_recorder_get_default_drive ();
1021
device = g_strdup (drive->device);
1022
nautilus_burn_drive_free (drive);
1029
rb_recorder_get_media_length (RBRecorder *recorder,
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);
1040
if (recorder->priv->drive)
1041
device = g_strdup (recorder->priv->drive->device);
1043
device = rb_recorder_get_default_device ();
1045
size = nautilus_burn_drive_get_media_size_from_path (device);
1047
#ifdef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
1048
secs = NAUTILUS_BURN_DRIVE_SIZE_TO_TIME (size);
1050
secs = SIZE_TO_TIME (size);
1061
/* Copyright (C) Bastien Nocera */
1062
/* From xine-lib, whoop */
1063
typedef struct __attribute__((__packed__)) {
1066
gint32 nSamplesPerSec;
1067
gint32 nAvgBytesPerSec;
1069
gint16 wBitsPerSample;
1072
#ifndef ATTRIBUTE_PACKED
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
1081
/* Copyright (C) Bastien Nocera */
1083
* http://www.onicos.com/staff/iz/formats/wav.html
1086
acb_wave_time (const char *filename)
1088
#define WAV_SIGNATURE_SIZE 16
1089
#define LPCM_BITRATE (16 * 44100 * 2)
1090
char buffer [WAV_SIGNATURE_SIZE];
1094
fd = open (filename, 0);
1096
return ACB_ERROR_OPEN;
1098
if (read (fd, buffer, WAV_SIGNATURE_SIZE) != WAV_SIGNATURE_SIZE)
1099
return ACB_ERROR_NOT_WAVE_TOO_SMALL;
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;
1115
if (read (fd, &len, sizeof(len)) != sizeof (len)) {
1117
return ACB_ERROR_NOT_WAVE_TOO_SMALL;
1120
if (GINT_FROM_LE (len) != 16) {
1122
g_print ("file len not defined\n");
1123
return ACB_ERROR_NOT_WAVE_FORMAT;
1126
wav = g_malloc (len);
1127
if (read (fd, wav, len) != len) {
1130
return ACB_ERROR_NOT_WAVE_FILE;
1135
if (wav->nChannels != 2
1136
|| wav->nSamplesPerSec != 44100
1137
|| wav->wBitsPerSample != 16) {
1139
return ACB_ERROR_NOT_WAVE_FORMAT;
1147
if (stat (filename, &buf) != 0)
1148
return ACB_ERROR_OPEN;
1150
return buf.st_size * 8 / LPCM_BITRATE;
1155
get_tracks_length (RBRecorder *recorder,
1161
if (!recorder->priv->tracks)
1164
for (l = recorder->priv->tracks; l; l = l->next) {
1165
NautilusBurnRecorderTrack *track = l->data;
1168
length = acb_wave_time (track->contents.audio.filename);
1170
g_warning (_("Could not get track time for file: %s"),
1171
track->contents.audio.filename);
1181
rb_recorder_burn_cancel (RBRecorder *recorder)
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);
1188
g_return_val_if_fail (recorder->priv->recorder != NULL, RB_RECORDER_RESULT_ERROR);
1190
nautilus_burn_recorder_cancel (recorder->priv->recorder, FALSE);
1192
return RB_RECORDER_RESULT_FINISHED;
1196
rb_recorder_burn (RBRecorder *recorder,
1200
NautilusBurnRecorder *cdrecorder;
1201
NautilusBurnRecorderWriteFlags flags;
1202
GError *local_error = NULL;
1205
gint64 tracks_length;
1206
gint64 media_length;
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);
1212
g_return_val_if_fail (recorder->priv->recorder == NULL, RB_RECORDER_RESULT_ERROR);
1214
if (!recorder->priv->tracks)
1215
return RB_RECORDER_RESULT_ERROR;
1217
if (!recorder->priv->drive) {
1218
char *default_device = rb_recorder_get_default_device ();
1220
if (!default_device) {
1221
g_warning (_("Could not determine default writer device"));
1222
return RB_RECORDER_RESULT_ERROR;
1225
rb_recorder_set_device (recorder, default_device, error);
1226
g_free (default_device);
1227
if (error && *error)
1228
return RB_RECORDER_RESULT_ERROR;
1231
tracks_length = get_tracks_length (recorder, error);
1232
if (tracks_length <= 0) {
1235
RB_RECORDER_ERROR_INTERNAL,
1236
_("Could not determine audio track durations."));
1237
return RB_RECORDER_RESULT_ERROR;
1240
media_length = rb_recorder_get_media_length (recorder, error);
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);
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."),
1254
media_duration_string);
1256
g_free (duration_string);
1257
g_free (media_duration_string);
1259
return RB_RECORDER_RESULT_ERROR;
1262
cdrecorder = nautilus_burn_recorder_new ();
1263
recorder->priv->recorder = cdrecorder;
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);
1276
flags |= NAUTILUS_BURN_RECORDER_WRITE_DUMMY_WRITE;
1278
flags |= NAUTILUS_BURN_RECORDER_WRITE_DEBUG;
1280
flags |= NAUTILUS_BURN_RECORDER_WRITE_DISC_AT_ONCE;
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,
1291
/* If nautilus-cd-burner == 2.10 */
1292
res = nautilus_burn_recorder_write_tracks (cdrecorder,
1293
recorder->priv->drive,
1294
recorder->priv->tracks,
1299
if (res == NAUTILUS_BURN_RECORDER_RESULT_FINISHED) {
1300
result = RB_RECORDER_RESULT_FINISHED;
1301
} else if (res == NAUTILUS_BURN_RECORDER_RESULT_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);
1310
msg = g_strdup (_("There was an error writing to the CD"));
1315
RB_RECORDER_ERROR_GENERAL,
1318
result = RB_RECORDER_RESULT_ERROR;
1321
result = RB_RECORDER_RESULT_CANCEL;
1324
g_object_unref (cdrecorder);
1325
recorder->priv->recorder = NULL;