1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of playlist source recorder object
5 * Copyright (C) 2002 Jorn Baayen <jorn@nl.linux.org>
6 * Copyright (C) 2003 Colin Walters <walters@gnome.org>
7 * Copyright (C) 2004-2006 William Jon McCann <mccann@jhu.edu>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <glib/gprintf.h>
34 #include <glib/gi18n.h>
36 #include <libgnomevfs/gnome-vfs-uri.h>
37 #include <libgnomevfs/gnome-vfs-utils.h>
38 #include <glade/glade.h>
39 #include <nautilus-burn-drive.h>
40 #include <nautilus-burn-drive-selection.h>
42 #ifndef NAUTILUS_BURN_CHECK_VERSION
43 #define NAUTILUS_BURN_CHECK_VERSION(a,b,c) FALSE
46 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
47 #include <nautilus-burn.h>
50 #include "rb-file-helpers.h"
51 #include "rb-glade-helpers.h"
52 #include "rb-preferences.h"
53 #include "rb-dialog.h"
56 #include "rb-playlist-source.h"
57 #include "rb-playlist-source-recorder.h"
59 #include "eel-gconf-extensions.h"
64 extern char *mkdtemp (char *template);
67 /* NAUTILUS_BURN_DRIVE_SIZE_TO_TIME was added in 2.12 */
68 #ifndef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
69 #define nautilus_burn_drive_eject _nautilus_burn_drive_eject
70 #define nautilus_burn_drive_new_from_path _nautilus_burn_drive_new_from_path
71 #define nautilus_burn_drive_media_type_get_string _nautilus_burn_drive_media_type_get_string
73 /* NAUTILUS_BURN_DRIVE_SIZE_TO_TIME was added in 2.14 */
74 #ifndef HAVE_BURN_DRIVE_UNREF
75 #define nautilus_burn_drive_unref nautilus_burn_drive_free
76 #define nautilus_burn_drive_ref nautilus_burn_drive_copy
79 #include "rb-recorder.h"
81 #define CONF_STATE_BURN_SPEED CONF_PREFIX "/state/burn_speed"
83 #define AUDIO_BYTERATE (2 * 44100 * 2)
84 #define MAX_PLAYLIST_DURATION 6000
86 static void rb_playlist_source_recorder_class_init (RBPlaylistSourceRecorderClass
*klass
);
87 static void rb_playlist_source_recorder_init (RBPlaylistSourceRecorder
*source
);
88 static void rb_playlist_source_recorder_finalize (GObject
*object
);
90 void rb_playlist_source_recorder_device_changed_cb (NautilusBurnDriveSelection
*selection
,
91 const char *device_path
,
92 RBPlaylistSourceRecorder
*source
);
94 GtkWidget
* rb_playlist_source_recorder_device_menu_create (void);
104 struct RBPlaylistSourceRecorderPrivate
112 RBRecorder
*recorder
;
120 GtkWidget
*multiple_copies_checkbutton
;
121 GtkWidget
*cancel_button
;
122 GtkWidget
*burn_button
;
123 GtkWidget
*message_label
;
124 GtkWidget
*progress_label
;
126 GtkWidget
*device_menu
;
127 GtkWidget
*speed_combobox
;
128 GtkWidget
*options_box
;
129 GtkWidget
*progress_frame
;
132 gboolean already_converted
;
133 gboolean handling_error
;
134 gboolean confirmed_exit
;
144 } RBPlaylistSourceRecorderSignalType
;
146 static guint rb_playlist_source_recorder_signals
[LAST_SIGNAL
] = { 0 };
148 #define RB_PLAYLIST_SOURCE_RECORDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAYLIST_SOURCE_RECORDER, RBPlaylistSourceRecorderPrivate))
150 G_DEFINE_TYPE(RBPlaylistSourceRecorder
, rb_playlist_source_recorder
, GTK_TYPE_DIALOG
)
153 rb_playlist_source_recorder_style_set (GtkWidget
*widget
,
154 GtkStyle
*previous_style
)
158 if (GTK_WIDGET_CLASS (rb_playlist_source_recorder_parent_class
)->style_set
)
159 GTK_WIDGET_CLASS (rb_playlist_source_recorder_parent_class
)->style_set (widget
, previous_style
);
161 dialog
= GTK_DIALOG (widget
);
163 gtk_container_set_border_width (GTK_CONTAINER (dialog
->vbox
), 12);
164 gtk_box_set_spacing (GTK_BOX (dialog
->vbox
), 24);
166 gtk_container_set_border_width (GTK_CONTAINER (dialog
->action_area
), 0);
167 gtk_box_set_spacing (GTK_BOX (dialog
->action_area
), 6);
171 rb_playlist_source_recorder_class_init (RBPlaylistSourceRecorderClass
*klass
)
173 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
174 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS (klass
);
176 widget_class
->style_set
= rb_playlist_source_recorder_style_set
;
178 object_class
->finalize
= rb_playlist_source_recorder_finalize
;
180 rb_playlist_source_recorder_signals
[NAME_CHANGED
] =
181 g_signal_new ("name_changed",
182 G_OBJECT_CLASS_TYPE (object_class
),
186 g_cclosure_marshal_VOID__STRING
,
191 rb_playlist_source_recorder_signals
[FILE_ADDED
] =
192 g_signal_new ("file_added",
193 G_OBJECT_CLASS_TYPE (object_class
),
197 g_cclosure_marshal_VOID__STRING
,
202 g_type_class_add_private (klass
, sizeof (RBPlaylistSourceRecorderPrivate
));
206 rb_playlist_source_recorder_device_menu_create (void)
211 widget
= nautilus_burn_drive_selection_new ();
212 g_object_set (widget
, "file-image", FALSE
, NULL
);
213 g_object_set (widget
, "show-recorders-only", TRUE
, NULL
);
215 value
= eel_gconf_get_string (CONF_STATE_BURN_DEVICE
);
217 nautilus_burn_drive_selection_set_device (NAUTILUS_BURN_DRIVE_SELECTION (widget
),
222 gtk_widget_show (widget
);
227 static const NautilusBurnDrive
*
228 lookup_current_recorder (RBPlaylistSourceRecorder
*source
)
230 const NautilusBurnDrive
*drive
;
232 drive
= nautilus_burn_drive_selection_get_drive (NAUTILUS_BURN_DRIVE_SELECTION (source
->priv
->device_menu
));
238 get_speed_selection (GtkWidget
*combobox
)
246 if (! gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox
), &iter
))
249 model
= gtk_combo_box_get_model (GTK_COMBO_BOX (combobox
));
250 gtk_tree_model_get (model
, &iter
, 1, &speed
, -1);
255 #ifndef HAVE_BURN_DRIVE_GET_WRITE_SPEEDS
257 #define nautilus_burn_drive_get_write_speeds get_write_speeds
260 get_write_speeds (NautilusBurnDrive
*drive
)
264 static int *write_speeds
= NULL
;
266 if (write_speeds
== NULL
) {
267 max_speed
= drive
->max_speed_write
;
268 write_speeds
= g_new0 (int, max_speed
+ 1);
270 for (i
= 0; i
< max_speed
; i
++) {
271 write_speeds
[i
] = max_speed
- i
;
275 return (const int*)write_speeds
;
280 update_speed_combobox (RBPlaylistSourceRecorder
*source
)
286 int default_speed_index
;
287 const NautilusBurnDrive
*drive
;
291 /* Find active recorder: */
292 drive
= lookup_current_recorder (source
);
294 /* add speed items: */
295 combobox
= source
->priv
->speed_combobox
;
296 model
= gtk_combo_box_get_model (GTK_COMBO_BOX (combobox
));
297 gtk_list_store_clear (GTK_LIST_STORE (model
));
299 gtk_list_store_append (GTK_LIST_STORE (model
), &iter
);
300 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
301 0, _("Maximum possible"),
305 default_speed
= eel_gconf_get_integer (CONF_STATE_BURN_SPEED
);
306 default_speed_index
= -1;
310 const int *write_speeds
;
312 write_speeds
= nautilus_burn_drive_get_write_speeds ((NautilusBurnDrive
*)drive
);
314 for (i
= 0; write_speeds
[i
] > 0; i
++) {
316 #ifdef NAUTILUS_BURN_DRIVE_CD_SPEED
317 name
= g_strdup_printf ("%d \303\227", (int)NAUTILUS_BURN_DRIVE_CD_SPEED (write_speeds
[i
]));
319 name
= g_strdup_printf ("%d \303\227", write_speeds
[i
]);
322 if (write_speeds
[i
] == default_speed
) {
323 default_speed_index
= i
+ 1;
326 gtk_list_store_append (GTK_LIST_STORE (model
), &iter
);
327 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
336 /* Disable speed if no items in list */
337 gtk_widget_set_sensitive (combobox
, i
> 0);
339 /* if the default speed was not set then make it the minimum for safety */
340 if (default_speed_index
== -1) {
341 default_speed_index
= i
;
344 /* for now assume equivalence between index in comboxbox and speed */
345 gtk_combo_box_set_active (GTK_COMBO_BOX (combobox
), default_speed_index
);
349 rb_playlist_source_recorder_device_changed_cb (NautilusBurnDriveSelection
*selection
,
350 const char *device_path
,
351 RBPlaylistSourceRecorder
*source
)
356 eel_gconf_set_string (CONF_STATE_BURN_DEVICE
, device_path
);
358 update_speed_combobox (source
);
362 set_media_device (RBPlaylistSourceRecorder
*source
)
367 device
= nautilus_burn_drive_selection_get_device (NAUTILUS_BURN_DRIVE_SELECTION (source
->priv
->device_menu
));
369 if (device
&& strcmp (device
, "")) {
370 rb_recorder_set_device (source
->priv
->recorder
, device
, &error
);
372 g_warning (_("Invalid writer device: %s"), device
);
373 /* ignore and let rb_recorder try to find a default */
379 set_message_text (RBPlaylistSourceRecorder
*source
,
387 va_start (args
, message
);
388 g_vasprintf (&text
, message
, args
);
391 markup
= g_strdup_printf ("%s", text
);
393 gtk_label_set_text (GTK_LABEL (source
->priv
->message_label
), markup
);
399 response_idle_cb (RBPlaylistSourceRecorder
*source
)
401 GDK_THREADS_ENTER ();
402 gtk_dialog_response (GTK_DIALOG (source
),
403 GTK_RESPONSE_CANCEL
);
404 GDK_THREADS_LEAVE ();
410 error_dialog_response_cb (GtkWidget
*dialog
,
414 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
416 gtk_widget_destroy (GTK_WIDGET (dialog
));
418 g_idle_add ((GSourceFunc
)response_idle_cb
, source
);
424 error_dialog (RBPlaylistSourceRecorder
*source
,
426 const char *secondary
,
433 va_start (args
, secondary
);
434 g_vasprintf (&text
, secondary
, args
);
437 dialog
= gtk_message_dialog_new (GTK_WINDOW (source
),
438 GTK_DIALOG_DESTROY_WITH_PARENT
,
443 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog
),
446 gtk_window_set_title (GTK_WINDOW (dialog
), "");
448 gtk_container_set_border_width (GTK_CONTAINER (dialog
), 6);
450 g_signal_connect (dialog
,
452 G_CALLBACK (error_dialog_response_cb
),
455 gtk_widget_show (dialog
);
460 /* Adapted from totem_time_to_string_text */
462 time_to_string_text (long time
)
464 char *secs
, *mins
, *hours
, *string
;
469 min
= (time
% (60 * 60)) / 60;
470 time
= time
- (min
* 60);
471 hour
= time
/ (60 * 60);
473 hours
= g_strdup_printf (ngettext ("%d hour", "%d hours", hour
), hour
);
475 mins
= g_strdup_printf (ngettext ("%d minute",
476 "%d minutes", min
), min
);
478 secs
= g_strdup_printf (ngettext ("%d second",
479 "%d seconds", sec
), sec
);
482 /* hour:minutes:seconds */
483 string
= g_strdup_printf (_("%s %s %s"), hours
, mins
, secs
);
484 } else if (min
> 0) {
485 /* minutes:seconds */
486 string
= g_strdup_printf (_("%s %s"), mins
, secs
);
487 } else if (sec
> 0) {
489 string
= g_strdup_printf (_("%s"), secs
);
492 string
= g_strdup (_("0 seconds"));
503 progress_set_time (GtkWidget
*progress
,
510 remaining
= time_to_string_text (seconds
);
511 text
= g_strdup_printf (_("About %s left"), remaining
);
514 text
= g_strdup (" ");
517 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress
), text
);
522 progress_set_fraction (GtkWidget
*progress
,
525 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress
), fraction
);
528 #ifndef NAUTILUS_BURN_DRIVE_SIZE_TO_TIME
529 /* copied from nautilus-burn-drive 2.12 */
531 _nautilus_burn_drive_eject (NautilusBurnDrive
*drive
)
536 g_return_val_if_fail (drive
!= NULL
, FALSE
);
538 if (drive
->device
== NULL
)
541 cmd
= g_strdup_printf ("eject %s", drive
->device
);
542 res
= g_spawn_command_line_sync (cmd
, NULL
, NULL
, NULL
, NULL
);
545 /* delay a bit to make sure eject finishes */
550 /* copied from nautilus-burn-drive 2.12 */
551 static NautilusBurnDrive
*
552 _nautilus_burn_drive_new_from_path (const char *device
)
555 NautilusBurnDrive
*drive
;
557 drives
= nautilus_burn_drive_get_list (FALSE
, FALSE
);
561 for (l
= drives
; l
!= NULL
; l
= l
->next
) {
562 NautilusBurnDrive
*d
= l
->data
;
563 if (g_str_equal (device
, d
->device
)) {
564 drive
= nautilus_burn_drive_ref (d
);
568 g_list_foreach (drives
, (GFunc
)nautilus_burn_drive_unref
, NULL
);
569 g_list_free (drives
);
574 /* copied from nautilus-burn-drive 2.12 */
576 _nautilus_burn_drive_media_type_get_string (NautilusBurnMediaType type
)
579 case NAUTILUS_BURN_MEDIA_TYPE_BUSY
:
580 return _("Could not determine media type because CD drive is busy");
581 case NAUTILUS_BURN_MEDIA_TYPE_ERROR
:
582 return _("Couldn't open media");
583 case NAUTILUS_BURN_MEDIA_TYPE_UNKNOWN
:
584 return _("Unknown Media");
585 case NAUTILUS_BURN_MEDIA_TYPE_CD
:
586 return _("Commercial CD or Audio CD");
587 case NAUTILUS_BURN_MEDIA_TYPE_CDR
:
589 case NAUTILUS_BURN_MEDIA_TYPE_CDRW
:
591 case NAUTILUS_BURN_MEDIA_TYPE_DVD
:
593 case NAUTILUS_BURN_MEDIA_TYPE_DVDR
:
594 return _("DVD-R, or DVD-RAM");
595 case NAUTILUS_BURN_MEDIA_TYPE_DVDRW
:
597 case NAUTILUS_BURN_MEDIA_TYPE_DVD_RAM
:
599 case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R
:
601 case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_RW
:
607 return _("Broken media type");
609 #endif /* NAUTILUS_BURN_DRIVE_SIZE_TO_TIME */
612 burn_cd (RBPlaylistSourceRecorder
*source
,
620 set_media_device (source
);
622 set_message_text (source
, _("Writing audio to CD"));
624 speed
= get_speed_selection (source
->priv
->speed_combobox
);
626 progress_set_fraction (source
->priv
->progress
, 0);
627 progress_set_time (source
->priv
->progress
, -1);
629 source
->priv
->burning
= TRUE
;
630 res
= rb_recorder_burn (source
->priv
->recorder
, speed
, error
);
631 source
->priv
->burning
= FALSE
;
633 if (res
== RB_RECORDER_RESULT_FINISHED
) {
634 NautilusBurnDrive
*drive
;
636 const char *finished_msg
;
638 finished_msg
= _("Finished creating audio CD.");
640 rb_shell_hidden_notify (source
->priv
->shell
, 0, finished_msg
, source
->priv
->cd_icon
, "", FALSE
);
642 /* save the write speed that was used */
643 eel_gconf_set_integer (CONF_STATE_BURN_SPEED
, speed
);
645 /* Always eject the disk after writing. Too many drives mess up otherwise */
646 drive
= (NautilusBurnDrive
*)lookup_current_recorder (source
);
647 nautilus_burn_drive_eject (drive
);
649 do_another
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (source
->priv
->multiple_copies_checkbutton
));
651 set_message_text (source
, finished_msg
);
652 gtk_widget_set_sensitive (GTK_WIDGET (source
), FALSE
);
653 g_idle_add ((GSourceFunc
)response_idle_cb
, source
);
656 set_message_text (source
, _("Finished creating audio CD.\nCreate another copy?"));
657 } else if (res
== RB_RECORDER_RESULT_ERROR
) {
658 set_message_text (source
, _("Writing failed. Try again?"));
660 set_message_text (source
, _("Writing cancelled. Try again?"));
663 progress_set_fraction (source
->priv
->progress
, 0);
664 progress_set_time (source
->priv
->progress
, -1);
666 gtk_widget_set_sensitive (GTK_WIDGET (source
->priv
->burn_button
), TRUE
);
667 gtk_widget_set_sensitive (GTK_WIDGET (source
->priv
->options_box
), TRUE
);
673 get_song_description (RBRecorderSong
*song
)
677 if (song
->artist
&& song
->title
)
678 desc
= g_strdup_printf ("%s - %s", song
->title
, song
->artist
);
679 else if (song
->title
)
680 desc
= g_strdup (song
->title
);
681 else if (song
->artist
)
682 desc
= g_strdup (song
->artist
);
688 write_file (RBPlaylistSourceRecorder
*source
,
691 RBRecorderSong
*song
= source
->priv
->current
->data
;
695 gtk_widget_set_sensitive (source
->priv
->progress_frame
, TRUE
);
697 cdtext
= get_song_description (song
);
699 markup
= g_markup_printf_escaped ("<i>Converting '%s'</i>", cdtext
);
700 gtk_label_set_markup (GTK_LABEL (source
->priv
->progress_label
), markup
);
703 rb_recorder_open (source
->priv
->recorder
, song
->uri
, cdtext
, error
);
707 if (error
&& *error
) {
711 rb_recorder_write (source
->priv
->recorder
, error
);
712 if (error
&& *error
) {
718 burn_cd_idle (RBPlaylistSourceRecorder
*source
)
720 GError
*error
= NULL
;
723 GDK_THREADS_ENTER ();
725 res
= burn_cd (source
, &error
);
727 error_dialog (source
,
728 _("Audio recording error"),
730 g_error_free (error
);
733 GDK_THREADS_LEAVE ();
738 eos_cb (RBRecorder
*recorder
,
741 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
742 GError
*error
= NULL
;
744 rb_debug ("Caught eos!");
746 rb_recorder_close (source
->priv
->recorder
, NULL
);
748 gtk_label_set_text (GTK_LABEL (source
->priv
->progress_label
), "");
750 if (source
->priv
->current
->next
) {
752 source
->priv
->current
= source
->priv
->current
->next
;
754 write_file (source
, &error
);
756 error_dialog (source
,
757 _("Audio Conversion Error"),
759 g_error_free (error
);
763 if (source
->priv
->timer
) {
764 g_timer_destroy (source
->priv
->timer
);
765 source
->priv
->timer
= NULL
;
768 source
->priv
->already_converted
= TRUE
;
770 g_idle_add ((GSourceFunc
)burn_cd_idle
, source
);
775 rb_playlist_source_recorder_error (RBPlaylistSourceRecorder
*source
,
779 if (source
->priv
->handling_error
) {
780 rb_debug ("Ignoring error: %s", error
->message
);
784 rb_debug ("Error: %s", error
->message
);
786 error_dialog (source
,
787 _("Recording error"),
790 source
->priv
->handling_error
= FALSE
;
791 rb_debug ("Exiting error hander");
795 error_cb (GObject
*object
,
799 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
801 if (source
->priv
->handling_error
)
804 source
->priv
->handling_error
= TRUE
;
806 rb_playlist_source_recorder_error (source
, error
);
810 track_progress_changed_cb (GObject
*object
,
815 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
816 double album_fraction
;
829 for (l
= source
->priv
->songs
; l
; l
= l
->next
) {
830 RBRecorderSong
*song
= l
->data
;
832 if (song
== source
->priv
->current
->data
) {
834 song_length
= song
->duration
;
836 total
+= song
->duration
;
839 position
= prev_total
+ song_length
* fraction
;
840 if (! source
->priv
->timer
) {
841 source
->priv
->timer
= g_timer_new ();
842 source
->priv
->start_pos
= position
;
845 album_fraction
= (float)position
/ (float)total
;
847 elapsed
= g_timer_elapsed (source
->priv
->timer
, NULL
);
849 rate
= (double)(position
- source
->priv
->start_pos
) / elapsed
;
852 album_secs
= ceil ((total
- position
) / rate
);
856 progress_set_time (source
->priv
->progress
, album_secs
);
857 progress_set_fraction (source
->priv
->progress
, album_fraction
);
860 interrupt_burn_dialog_response_cb (GtkDialog
*dialog
,
864 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
866 if (response_id
== GTK_RESPONSE_ACCEPT
) {
867 if (source
->priv
->burning
) {
868 rb_recorder_burn_cancel (source
->priv
->recorder
);
870 source
->priv
->confirmed_exit
= TRUE
;
871 gtk_dialog_response (GTK_DIALOG (source
),
872 GTK_RESPONSE_CANCEL
);
875 source
->priv
->confirmed_exit
= FALSE
;
878 gtk_widget_destroy (GTK_WIDGET (dialog
));
882 response_cb (GtkDialog
*dialog
,
885 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (dialog
);
886 GError
*error
= NULL
;
888 /* Act only on response IDs we recognize */
889 if (!(response_id
== GTK_RESPONSE_ACCEPT
890 || response_id
== GTK_RESPONSE_CANCEL
891 || response_id
== GTK_RESPONSE_DELETE_EVENT
)) {
892 g_signal_stop_emission_by_name (dialog
, "response");
896 if (response_id
== GTK_RESPONSE_CANCEL
|| response_id
== GTK_RESPONSE_DELETE_EVENT
) {
897 if (source
->priv
->burning
898 && !source
->priv
->confirmed_exit
) {
899 GtkWidget
*interrupt_dialog
;
901 source
->priv
->confirmed_exit
= FALSE
;
903 interrupt_dialog
= gtk_message_dialog_new (GTK_WINDOW (dialog
),
904 GTK_DIALOG_DESTROY_WITH_PARENT
,
905 GTK_MESSAGE_QUESTION
,
907 _("Do you wish to interrupt writing this disc?"));
909 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (interrupt_dialog
),
910 _("This may result in an unusable disc."));
912 gtk_window_set_title (GTK_WINDOW (interrupt_dialog
), "");
914 gtk_container_set_border_width (GTK_CONTAINER (interrupt_dialog
), 6);
916 gtk_dialog_add_buttons (GTK_DIALOG (interrupt_dialog
),
917 _("_Cancel"), GTK_RESPONSE_CANCEL
,
918 _("_Interrupt"), GTK_RESPONSE_ACCEPT
,
921 gtk_dialog_set_default_response (GTK_DIALOG (interrupt_dialog
),
922 GTK_RESPONSE_CANCEL
);
924 g_signal_connect (interrupt_dialog
,
926 G_CALLBACK (interrupt_burn_dialog_response_cb
),
929 gtk_widget_show (interrupt_dialog
);
931 g_signal_stop_emission_by_name (dialog
, "response");
936 if (response_id
== GTK_RESPONSE_ACCEPT
) {
937 rb_playlist_source_recorder_start (source
, &error
);
939 error_dialog (source
,
940 _("Could not create audio CD"),
942 g_error_free (error
);
944 g_signal_stop_emission_by_name (dialog
, "response");
949 insert_media_request_cb (RBRecorder
*recorder
,
951 gboolean can_rewrite
,
955 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
962 msg
= N_("Please make sure another application is not using the drive.");
963 title
= N_("Drive is busy");
964 } else if (is_reload
&& can_rewrite
) {
965 msg
= N_("Please put a rewritable or blank CD in the drive.");
966 title
= N_("Insert a rewritable or blank CD");
967 } else if (is_reload
&& !can_rewrite
) {
968 msg
= N_("Please put a blank CD in the drive.");
969 title
= N_("Insert a blank CD");
970 } else if (can_rewrite
) {
971 msg
= N_("Please replace the disc in the drive with a rewritable or blank CD.");
972 title
= N_("Reload a rewritable or blank CD");
974 msg
= N_("Please replace the disc in the drive with a blank CD.");
975 title
= N_("Reload a blank CD");
978 GDK_THREADS_ENTER ();
979 dialog
= gtk_message_dialog_new (GTK_WINDOW (source
),
980 GTK_DIALOG_DESTROY_WITH_PARENT
,
982 GTK_BUTTONS_OK_CANCEL
,
985 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog
), msg
);
987 gtk_window_set_title (GTK_WINDOW (dialog
), "");
989 gtk_container_set_border_width (GTK_CONTAINER (dialog
), 6);
991 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
993 gtk_widget_destroy (dialog
);
994 GDK_THREADS_LEAVE ();
996 if (res
== GTK_RESPONSE_CANCEL
)
1003 burn_progress_changed_cb (RBRecorder
*recorder
,
1008 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
1010 progress_set_fraction (source
->priv
->progress
, fraction
);
1011 progress_set_time (source
->priv
->progress
, secs
);
1015 burn_action_changed_cb (RBRecorder
*recorder
,
1016 RBRecorderAction action
,
1019 RBPlaylistSourceRecorder
*source
= RB_PLAYLIST_SOURCE_RECORDER (data
);
1025 case RB_RECORDER_ACTION_FILE_CONVERTING
:
1026 text
= N_("Converting audio tracks");
1028 case RB_RECORDER_ACTION_DISC_PREPARING_WRITE
:
1029 text
= N_("Preparing to write CD");
1031 case RB_RECORDER_ACTION_DISC_WRITING
:
1032 text
= N_("Writing CD");
1034 case RB_RECORDER_ACTION_DISC_FIXATING
:
1035 text
= N_("Finishing write");
1037 case RB_RECORDER_ACTION_DISC_BLANKING
:
1038 text
= N_("Erasing CD");
1041 g_warning (_("Unhandled action in burn_action_changed_cb"));
1045 set_message_text (source
, text
);
1049 ask_rewrite_disc (RBPlaylistSourceRecorder
*source
,
1056 NautilusBurnMediaType type
;
1058 NautilusBurnDrive
*drive
;
1060 #if NAUTILUS_BURN_CHECK_VERSION(2,15,3)
1061 drive
= nautilus_burn_drive_monitor_get_drive_for_device (nautilus_burn_get_drive_monitor (),
1064 drive
= nautilus_burn_drive_new_from_path (device
);
1067 type
= nautilus_burn_drive_get_media_type (drive
);
1069 msg
= g_strdup_printf (_("This %s appears to have information already recorded on it."),
1070 nautilus_burn_drive_media_type_get_string (type
));
1072 dialog
= gtk_message_dialog_new (GTK_WINDOW (source
),
1073 GTK_DIALOG_DESTROY_WITH_PARENT
,
1074 GTK_MESSAGE_WARNING
,
1076 "%s", _("Erase information on this disc?"));
1078 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog
), msg
);
1081 gtk_window_set_title (GTK_WINDOW (dialog
), "");
1083 image
= gtk_image_new_from_stock (GTK_STOCK_REFRESH
, GTK_ICON_SIZE_BUTTON
);
1084 gtk_widget_show (image
);
1085 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
), _("_Try Another"), RB_RECORDER_RESPONSE_RETRY
);
1086 g_object_set (button
, "image", image
, NULL
);
1088 gtk_dialog_add_button (GTK_DIALOG (dialog
), GTK_STOCK_CANCEL
, RB_RECORDER_RESPONSE_CANCEL
);
1090 image
= gtk_image_new_from_stock (GTK_STOCK_CLEAR
, GTK_ICON_SIZE_BUTTON
);
1091 gtk_widget_show (image
);
1092 button
= gtk_dialog_add_button (GTK_DIALOG (dialog
), _("_Erase Disc"), RB_RECORDER_RESPONSE_ERASE
);
1093 g_object_set (button
, "image", image
, NULL
);
1095 gtk_dialog_set_default_response (GTK_DIALOG (dialog
),
1096 RB_RECORDER_RESPONSE_CANCEL
);
1098 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
1100 gtk_widget_destroy (dialog
);
1102 if (res
== RB_RECORDER_RESPONSE_RETRY
) {
1103 nautilus_burn_drive_eject (drive
);
1106 nautilus_burn_drive_unref (drive
);
1112 warn_data_loss_cb (RBRecorder
*recorder
,
1113 RBPlaylistSourceRecorder
*source
)
1118 device
= rb_recorder_get_device (recorder
, NULL
);
1119 GDK_THREADS_ENTER();
1120 res
= ask_rewrite_disc (source
, device
);
1121 GDK_THREADS_LEAVE();
1129 setup_speed_combobox (GtkWidget
*combobox
)
1131 GtkCellRenderer
*cell
;
1132 GtkListStore
*store
;
1134 store
= gtk_list_store_new (2, G_TYPE_STRING
, G_TYPE_INT
);
1136 gtk_combo_box_set_model (GTK_COMBO_BOX (combobox
),
1137 GTK_TREE_MODEL (store
));
1138 g_object_unref (store
);
1140 cell
= gtk_cell_renderer_text_new ();
1141 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox
), cell
, TRUE
);
1142 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox
), cell
,
1148 delete_event_handler (GtkWidget
*widget
,
1152 /* emit response signal */
1153 gtk_dialog_response (GTK_DIALOG (widget
), GTK_RESPONSE_DELETE_EVENT
);
1155 /* Do the destroy by default */
1160 rb_playlist_source_recorder_init (RBPlaylistSourceRecorder
*source
)
1163 GError
*error
= NULL
;
1167 PangoAttrList
*pattrlist
;
1168 PangoAttribute
*attr
;
1170 g_signal_connect (GTK_DIALOG (source
),
1172 G_CALLBACK (delete_event_handler
),
1175 source
->priv
= RB_PLAYLIST_SOURCE_RECORDER_GET_PRIVATE (source
);
1177 gtk_window_set_resizable (GTK_WINDOW (source
), FALSE
);
1178 gtk_dialog_set_has_separator (GTK_DIALOG (source
), FALSE
);
1179 source
->priv
->cancel_button
= gtk_dialog_add_button (GTK_DIALOG (source
),
1180 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
);
1182 source
->priv
->burn_button
= gtk_button_new ();
1183 GTK_WIDGET_SET_FLAGS (source
->priv
->burn_button
, GTK_CAN_DEFAULT
);
1185 widget
= gtk_alignment_new (0.5, 0.5, 0, 0);
1186 gtk_container_add (GTK_CONTAINER (source
->priv
->burn_button
), widget
);
1187 gtk_widget_show (widget
);
1188 hbox
= gtk_hbox_new (FALSE
, 6);
1189 gtk_container_add (GTK_CONTAINER (widget
), hbox
);
1190 gtk_widget_show (hbox
);
1191 widget
= gtk_image_new_from_stock (GTK_STOCK_CDROM
, GTK_ICON_SIZE_BUTTON
);
1192 source
->priv
->cd_icon
= widget
;
1193 g_object_ref (source
->priv
->cd_icon
);
1194 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
1195 gtk_widget_show (widget
);
1196 widget
= gtk_label_new_with_mnemonic (_("C_reate"));
1197 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
1198 gtk_widget_show (widget
);
1199 gtk_dialog_add_action_widget (GTK_DIALOG (source
),
1200 source
->priv
->burn_button
,
1201 GTK_RESPONSE_ACCEPT
);
1202 gtk_widget_show (source
->priv
->burn_button
);
1204 gtk_dialog_set_default_response (GTK_DIALOG (source
), GTK_RESPONSE_ACCEPT
);
1206 xml
= rb_glade_xml_new ("recorder.glade",
1210 source
->priv
->vbox
= glade_xml_get_widget (xml
, "recorder_vbox");
1212 source
->priv
->message_label
= glade_xml_get_widget (xml
, "message_label");
1213 source
->priv
->progress_label
= glade_xml_get_widget (xml
, "progress_label");
1215 source
->priv
->progress
= glade_xml_get_widget (xml
, "progress");
1216 gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR (source
->priv
->progress
), PANGO_ELLIPSIZE_END
);
1217 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (source
->priv
->progress
), " ");
1218 gtk_widget_set_size_request (source
->priv
->progress
, 400, -1);
1220 source
->priv
->progress_frame
= glade_xml_get_widget (xml
, "progress_frame");
1222 source
->priv
->options_box
= glade_xml_get_widget (xml
, "options_box");
1223 source
->priv
->device_menu
= glade_xml_get_widget (xml
, "device_menu");
1224 source
->priv
->multiple_copies_checkbutton
= glade_xml_get_widget (xml
, "multiple_copies_checkbutton");
1226 source
->priv
->speed_combobox
= glade_xml_get_widget (xml
, "speed_combobox");
1227 setup_speed_combobox (source
->priv
->speed_combobox
);
1229 widget
= glade_xml_get_widget (xml
, "device_label");
1230 gtk_label_set_mnemonic_widget (GTK_LABEL (widget
), source
->priv
->device_menu
);
1232 rb_glade_boldify_label (xml
, "progress_frame_label");
1233 rb_glade_boldify_label (xml
, "options_expander_label");
1235 pattrlist
= pango_attr_list_new ();
1236 attr
= pango_attr_weight_new (PANGO_WEIGHT_BOLD
);
1237 attr
->start_index
= 0;
1238 attr
->end_index
= G_MAXINT
;
1239 pango_attr_list_insert (pattrlist
, attr
);
1241 font_size
= pango_font_description_get_size (GTK_WIDGET (source
->priv
->message_label
)->style
->font_desc
);
1242 attr
= pango_attr_size_new (font_size
* 1.2);
1243 attr
->start_index
= 0;
1244 attr
->end_index
= G_MAXINT
;
1245 pango_attr_list_insert (pattrlist
, attr
);
1247 gtk_label_set_attributes (GTK_LABEL (source
->priv
->message_label
), pattrlist
);
1249 pango_attr_list_unref (pattrlist
);
1251 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (source
)->vbox
),
1254 gtk_widget_show_all (source
->priv
->vbox
);
1256 source
->priv
->recorder
= rb_recorder_new (&error
);
1259 char *msg
= g_strdup_printf (_("Failed to create the recorder: %s"),
1261 g_error_free (error
);
1262 dialog
= gtk_message_dialog_new (NULL
, GTK_DIALOG_MODAL
,
1266 gtk_dialog_run (GTK_DIALOG (dialog
));
1271 update_speed_combobox (source
);
1272 g_signal_connect (source
->priv
->device_menu
, "device-changed",
1273 G_CALLBACK (rb_playlist_source_recorder_device_changed_cb
),
1276 g_signal_connect_object (G_OBJECT (source
->priv
->recorder
), "eos",
1277 G_CALLBACK (eos_cb
), source
, 0);
1279 g_signal_connect_object (G_OBJECT (source
->priv
->recorder
), "error",
1280 G_CALLBACK (error_cb
), source
, 0);
1282 g_signal_connect_object (G_OBJECT (source
->priv
->recorder
), "action-changed",
1283 G_CALLBACK (burn_action_changed_cb
), source
, 0);
1285 g_signal_connect_object (G_OBJECT (source
->priv
->recorder
), "track-progress-changed",
1286 G_CALLBACK (track_progress_changed_cb
), source
, 0);
1288 g_signal_connect_object (G_OBJECT (source
->priv
->recorder
), "insert-media-request",
1289 G_CALLBACK (insert_media_request_cb
), source
, 0);
1291 g_signal_connect_object (G_OBJECT (source
->priv
->recorder
), "warn-data-loss",
1292 G_CALLBACK (warn_data_loss_cb
), source
, 0);
1294 g_signal_connect_object (G_OBJECT (source
->priv
->recorder
), "burn-progress-changed",
1295 G_CALLBACK (burn_progress_changed_cb
), source
, 0);
1297 g_signal_connect (GTK_DIALOG (source
), "response",
1298 G_CALLBACK (response_cb
), NULL
);
1301 static RBRecorderSong
*
1302 recorder_song_new ()
1304 RBRecorderSong
*song
= g_new0 (RBRecorderSong
, 1);
1309 recorder_song_free (RBRecorderSong
*song
)
1311 g_return_if_fail (song
!= NULL
);
1313 g_free (song
->title
);
1319 free_song_list (GSList
*songs
)
1323 for (l
= songs
; l
; l
= l
->next
) {
1324 recorder_song_free ((RBRecorderSong
*)l
->data
);
1327 g_slist_free (songs
);
1332 rb_playlist_source_recorder_finalize (GObject
*object
)
1334 RBPlaylistSourceRecorder
*source
;
1336 g_return_if_fail (object
!= NULL
);
1337 g_return_if_fail (RB_IS_PLAYLIST_SOURCE_RECORDER (object
));
1339 source
= RB_PLAYLIST_SOURCE_RECORDER (object
);
1341 g_return_if_fail (source
->priv
!= NULL
);
1343 rb_debug ("Finalize source recorder");
1345 g_object_unref (source
->priv
->shell
);
1347 g_object_unref (source
->priv
->cd_icon
);
1349 g_free (source
->priv
->name
);
1350 source
->priv
->name
= NULL
;
1352 free_song_list (source
->priv
->songs
);
1354 g_object_unref (source
->priv
->recorder
);
1355 source
->priv
->recorder
= NULL
;
1357 if (source
->priv
->tmp_dir
) {
1358 if (rmdir (source
->priv
->tmp_dir
) < 0)
1359 g_warning (_("Could not remove temporary directory '%s': %s"),
1360 source
->priv
->tmp_dir
,
1361 g_strerror (errno
));
1362 g_free (source
->priv
->tmp_dir
);
1363 source
->priv
->tmp_dir
= NULL
;
1366 G_OBJECT_CLASS (rb_playlist_source_recorder_parent_class
)->finalize (object
);
1370 rb_playlist_source_recorder_new (GtkWidget
*parent
,
1375 RBPlaylistSourceRecorder
*source
;
1377 result
= g_object_new (RB_TYPE_PLAYLIST_SOURCE_RECORDER
,
1378 "title", _("Create Audio CD"),
1381 source
= RB_PLAYLIST_SOURCE_RECORDER (result
);
1383 source
->priv
->parent
= gtk_widget_get_toplevel (parent
);
1385 gtk_window_set_transient_for (GTK_WINDOW (source
),
1386 GTK_WINDOW (source
->priv
->parent
));
1387 gtk_window_set_destroy_with_parent (GTK_WINDOW (source
), TRUE
);
1390 source
->priv
->shell
= g_object_ref (shell
);
1393 source
->priv
->name
= g_strdup (name
);
1395 set_message_text (source
, _("Create audio CD from '%s'?"), name
);
1402 rb_playlist_source_recorder_set_name (RBPlaylistSourceRecorder
*source
,
1406 g_return_if_fail (source
!= NULL
);
1407 g_return_if_fail (RB_IS_PLAYLIST_SOURCE_RECORDER (source
));
1409 g_return_if_fail (name
!= NULL
);
1411 g_free (source
->priv
->name
);
1412 source
->priv
->name
= g_strdup (name
);
1414 g_signal_emit (G_OBJECT (source
),
1415 rb_playlist_source_recorder_signals
[NAME_CHANGED
],
1421 rb_playlist_source_recorder_add_from_model (RBPlaylistSourceRecorder
*source
,
1422 GtkTreeModel
*model
,
1423 RBPlaylistSourceIterFunc func
,
1428 GSList
*songs
= NULL
;
1432 g_return_val_if_fail (source
!= NULL
, FALSE
);
1433 g_return_val_if_fail (RB_IS_PLAYLIST_SOURCE_RECORDER (source
), FALSE
);
1435 g_return_val_if_fail (model
!= NULL
, FALSE
);
1437 if (! gtk_tree_model_get_iter_first (model
, &iter
)) {
1440 RB_RECORDER_ERROR_GENERAL
,
1441 _("Unable to build an audio track list."));
1446 /* Make sure we can use all of the songs before we
1447 modify the song list */
1450 RBRecorderSong
*song
= recorder_song_new ();
1453 res
= func (model
, &iter
, &song
->uri
, &song
->artist
, &song
->title
, &song
->duration
);
1458 RB_RECORDER_ERROR_GENERAL
,
1459 _("Unable to build an audio track list."));
1463 length
+= song
->duration
;
1464 if (length
> MAX_PLAYLIST_DURATION
) {
1468 RB_RECORDER_ERROR_GENERAL
,
1469 _("This playlist is too long to write to an audio CD."));
1473 songs
= g_slist_append (songs
, song
);
1474 } while (gtk_tree_model_iter_next (model
, &iter
));
1477 free_song_list (songs
);
1482 /* now that we've checked all the songs, add them to the song list */
1483 for (l
= songs
; l
; l
= l
->next
) {
1484 RBRecorderSong
*song
= l
->data
;
1486 source
->priv
->songs
= g_slist_append (source
->priv
->songs
, song
);
1488 g_signal_emit (G_OBJECT (source
),
1489 rb_playlist_source_recorder_signals
[FILE_ADDED
],
1498 rb_playlist_source_recorder_get_total_duration (RBPlaylistSourceRecorder
*source
)
1503 for (l
= source
->priv
->songs
; l
; l
= l
->next
) {
1504 RBRecorderSong
*song
= l
->data
;
1505 length
+= song
->duration
;
1512 rb_playlist_source_recorder_estimate_total_size (RBPlaylistSourceRecorder
*source
)
1516 length
= rb_playlist_source_recorder_get_total_duration (source
);
1518 return length
* AUDIO_BYTERATE
;
1522 check_dir_has_space (const char *path
,
1523 guint64 bytes_needed
)
1525 GnomeVFSResult result
= GNOME_VFS_OK
;
1526 GnomeVFSURI
*dir_uri
= NULL
;
1527 GnomeVFSFileSize free_bytes
= 0;
1529 if (!g_file_test (path
, G_FILE_TEST_IS_DIR
))
1532 dir_uri
= gnome_vfs_uri_new (path
);
1533 if (dir_uri
== NULL
) {
1534 g_warning (_("Cannot get free space at %s"), path
);
1538 result
= gnome_vfs_get_volume_free_space (dir_uri
, &free_bytes
);
1540 gnome_vfs_uri_unref (dir_uri
);
1542 if (result
!= GNOME_VFS_OK
) {
1543 g_warning (_("Cannot get free space at %s"), path
);
1547 if (bytes_needed
>= free_bytes
)
1554 find_tmp_dir (RBPlaylistSourceRecorder
*source
,
1555 guint64 bytes_needed
,
1560 g_return_val_if_fail (source
!= NULL
, NULL
);
1561 g_return_val_if_fail (RB_IS_PLAYLIST_SOURCE_RECORDER (source
), NULL
);
1563 /* Use a configurable temporary directory? */
1565 if (path
&& strcmp (path
, "")
1566 && check_dir_has_space (path
, bytes_needed
))
1568 else if (g_get_tmp_dir () &&
1569 check_dir_has_space (g_get_tmp_dir (), bytes_needed
))
1570 return g_strdup (g_get_tmp_dir ());
1571 else if (g_get_home_dir () &&
1572 check_dir_has_space (g_get_home_dir (), bytes_needed
))
1573 return g_strdup (g_get_home_dir ());
1579 check_tmp_dir (RBPlaylistSourceRecorder
*source
,
1585 guint64 bytes_needed
;
1587 g_return_val_if_fail (source
!= NULL
, FALSE
);
1588 g_return_val_if_fail (RB_IS_PLAYLIST_SOURCE_RECORDER (source
), FALSE
);
1590 bytes_needed
= rb_playlist_source_recorder_estimate_total_size (source
);
1592 path
= find_tmp_dir (source
, bytes_needed
, error
);
1596 template = g_build_filename (path
, "rb-burn-tmp-XXXXXX", NULL
);
1597 subdir
= mkdtemp (template);
1602 g_free (source
->priv
->tmp_dir
);
1603 source
->priv
->tmp_dir
= subdir
;
1604 rb_recorder_set_tmp_dir (source
->priv
->recorder
,
1605 source
->priv
->tmp_dir
,
1608 if (error
&& *error
)
1615 check_media_length (RBPlaylistSourceRecorder
*source
,
1618 gint64 duration
= rb_playlist_source_recorder_get_total_duration (source
);
1619 char *message
= NULL
;
1620 gint64 media_duration
;
1621 char *duration_string
;
1623 media_duration
= rb_recorder_get_media_length (source
->priv
->recorder
, NULL
);
1624 duration_string
= g_strdup_printf ("%" G_GINT64_FORMAT
, duration
/ 60);
1626 /* Only check if the playlist is greater than 74 minutes */
1627 if ((media_duration
< 0) && (duration
> 4440)) {
1628 message
= g_strdup_printf (_("This playlist is %s minutes long. "
1629 "This exceeds the length of a standard audio CD. "
1630 "If the destination media is larger than a standard audio CD "
1631 "please insert it in the drive and try again."),
1635 g_free (duration_string
);
1638 error_dialog (source
,
1639 _("Playlist too long"),
1650 rb_playlist_source_recorder_start (RBPlaylistSourceRecorder
*source
,
1653 g_return_if_fail (source
!= NULL
);
1654 g_return_if_fail (RB_IS_PLAYLIST_SOURCE_RECORDER (source
));
1656 source
->priv
->current
= source
->priv
->songs
;
1658 gtk_widget_set_sensitive (source
->priv
->burn_button
, FALSE
);
1659 gtk_widget_set_sensitive (source
->priv
->options_box
, FALSE
);
1661 if (source
->priv
->already_converted
) {
1662 g_idle_add ((GSourceFunc
)burn_cd_idle
, source
);
1666 set_media_device (source
);
1668 is_ok
= check_media_length (source
, error
);
1673 is_ok
= check_tmp_dir (source
, error
);
1675 guint64 mib_needed
= rb_playlist_source_recorder_estimate_total_size (source
) / 1048576;
1676 char *mib_needed_string
= g_strdup_printf ("%" G_GUINT64_FORMAT
, mib_needed
);
1678 error_dialog (source
,
1679 _("Could not find temporary space!"),
1680 _("Could not find enough temporary space to convert audio tracks. %s MiB required."),
1682 g_free (mib_needed_string
);
1687 write_file (source
, error
);