diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c
index 8b7af2d..e26884d 100644
--- a/src/empathy-call-window.c
+++ b/src/empathy-call-window.c
@@ -116,6 +116,8 @@ struct _EmpathyCallWindowPriv
 
   GtkUIManager *ui_manager;
   GtkWidget *errors_vbox;
+  /* widget displays the video received from the remote user. This widget is
+   * alive only during call. */
   GtkWidget *video_output;
   GtkWidget *video_preview;
   GtkWidget *remote_user_avatar_widget;
@@ -195,6 +197,9 @@ struct _EmpathyCallWindowPriv
   gboolean sidebar_was_visible_before_fs;
   gint original_width_before_fs;
   gint original_height_before_fs;
+
+  /* TRUE if the call should be started when the pipeline is playing */
+  gboolean start_call_when_playing;
 };
 
 #define GET_PRIV(o) \
@@ -518,9 +523,6 @@ empathy_call_window_mic_volume_changed_cb (GtkAdjustment *adj,
   EmpathyCallWindowPriv *priv = GET_PRIV (self);
   gdouble volume;
 
-  if (priv->audio_input == NULL)
-    return;
-
   volume = gtk_adjustment_get_value (adj)/100.0;
 
   /* Don't store the volume because of muting */
@@ -592,19 +594,17 @@ empathy_call_window_create_audio_input (EmpathyCallWindow *self)
 }
 
 static void
-empathy_call_window_setup_remote_frame (GstBus *bus, EmpathyCallWindow *self)
+create_video_output_widget (EmpathyCallWindow *self)
 {
   EmpathyCallWindowPriv *priv = GET_PRIV (self);
+  GstBus *bus;
 
-  /* Initializing all the content (UI and output gst elements) related to the
-     remote contact */
-  priv->remote_user_output_hbox = gtk_hbox_new (FALSE, 0);
-
-  priv->remote_user_avatar_widget = gtk_image_new ();
-  gtk_box_pack_start (GTK_BOX (priv->remote_user_output_hbox),
-      priv->remote_user_avatar_widget, TRUE, TRUE, 0);
+  g_assert (priv->video_output == NULL);
+  g_assert (priv->pipeline != NULL);
 
+  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
   priv->video_output = empathy_video_widget_new (bus);
+
   gtk_box_pack_start (GTK_BOX (priv->remote_user_output_hbox),
       priv->video_output, TRUE, TRUE, 0);
 
@@ -613,35 +613,37 @@ empathy_call_window_setup_remote_frame (GstBus *bus, EmpathyCallWindow *self)
   g_signal_connect (G_OBJECT (priv->video_output), "button-press-event",
       G_CALLBACK (empathy_call_window_video_button_press_cb), self);
 
-  gtk_container_add (GTK_CONTAINER (priv->remote_user_output_frame),
-      priv->remote_user_output_hbox);
+  g_object_unref (bus);
+}
+
+static void
+create_audio_output (EmpathyCallWindow *self)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (self);
 
+  g_assert (priv->audio_output == NULL);
   priv->audio_output = empathy_audio_sink_new ();
   gst_object_ref (priv->audio_output);
   gst_object_sink (priv->audio_output);
 }
 
 static void
-empathy_call_window_setup_self_frame (GstBus *bus, EmpathyCallWindow *self)
+create_video_input (EmpathyCallWindow *self)
 {
   EmpathyCallWindowPriv *priv = GET_PRIV (self);
 
-  /* Initializing all the content (UI and input gst elements) related to the
-     self contact, except for the video preview widget. This widget is only
-     initialized when the "show video preview" option is activated */
-  priv->self_user_output_hbox = gtk_hbox_new (FALSE, 0);
-
-  priv->self_user_avatar_widget = gtk_image_new ();
-  gtk_box_pack_start (GTK_BOX (priv->self_user_output_hbox),
-      priv->self_user_avatar_widget, TRUE, TRUE, 0);
-
-  gtk_container_add (GTK_CONTAINER (priv->self_user_output_frame),
-      priv->self_user_output_hbox);
-
+  g_assert (priv->video_input == NULL);
   priv->video_input = empathy_video_src_new ();
   gst_object_ref (priv->video_input);
   gst_object_sink (priv->video_input);
+}
 
+static void
+create_audio_input (EmpathyCallWindow *self)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (self);
+
+  g_assert (priv->audio_input == NULL);
   priv->audio_input = empathy_audio_src_new ();
   gst_object_ref (priv->audio_input);
   gst_object_sink (priv->audio_input);
@@ -652,46 +654,74 @@ empathy_call_window_setup_self_frame (GstBus *bus, EmpathyCallWindow *self)
 }
 
 static void
-empathy_call_window_setup_video_preview (EmpathyCallWindow *window)
+add_video_preview_to_pipeline (EmpathyCallWindow *self)
 {
-  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+  EmpathyCallWindowPriv *priv = GET_PRIV (self);
   GstElement *preview;
-  GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
 
-  if (priv->video_preview != NULL)
-    {
-      /* Since the video preview and the video tee are initialized and freed
-         at the same time, if one is initialized, then the other one should
-         be too. */
-      g_assert (priv->video_tee != NULL);
-      return;
-    }
+  g_assert (priv->video_preview != NULL);
+  g_assert (priv->pipeline != NULL);
+  g_assert (priv->video_input != NULL);
+  g_assert (priv->video_tee != NULL);
+
+  preview = empathy_video_widget_get_element (
+      EMPATHY_VIDEO_WIDGET (priv->video_preview));
+  gst_bin_add_many (GST_BIN (priv->pipeline), priv->video_input,
+      priv->video_tee, preview, NULL);
+  gst_element_link_many (priv->video_input, priv->video_tee,
+      preview, NULL);
+}
+
+static void
+create_video_preview (EmpathyCallWindow *self)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (self);
+  GstBus *bus;
 
-  DEBUG ("Create video preview");
+  g_assert (priv->video_preview == NULL);
   g_assert (priv->video_tee == NULL);
 
-  priv->video_tee = gst_element_factory_make ("tee", NULL);
-  gst_object_ref (priv->video_tee);
-  gst_object_sink (priv->video_tee);
+  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
 
   priv->video_preview = empathy_video_widget_new_with_size (bus,
       SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH);
   g_object_set (priv->video_preview, "sync", FALSE, "async", TRUE, NULL);
+
   gtk_box_pack_start (GTK_BOX (priv->self_user_output_hbox),
       priv->video_preview, TRUE, TRUE, 0);
 
-  preview = empathy_video_widget_get_element (
-      EMPATHY_VIDEO_WIDGET (priv->video_preview));
-  gst_bin_add_many (GST_BIN (priv->pipeline), priv->video_input,
-      priv->video_tee, preview, NULL);
-  gst_element_link_many (priv->video_input, priv->video_tee,
-      preview, NULL);
+  priv->video_tee = gst_element_factory_make ("tee", NULL);
+  gst_object_ref (priv->video_tee);
+  gst_object_sink (priv->video_tee);
 
   g_object_unref (bus);
+}
+
+static void
+play_camera (EmpathyCallWindow *window,
+    gboolean play)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+  GstElement *preview;
+  GstState state;
+
+  if (priv->video_preview == NULL)
+    {
+      create_video_preview (window);
+      add_video_preview_to_pipeline (window);
+    }
 
-  gst_element_set_state (preview, GST_STATE_PLAYING);
-  gst_element_set_state (priv->video_input, GST_STATE_PLAYING);
-  gst_element_set_state (priv->video_tee, GST_STATE_PLAYING);
+  if (play)
+    state = GST_STATE_PLAYING;
+  else
+    state = GST_STATE_NULL;
+
+  preview = empathy_video_widget_get_element (
+      EMPATHY_VIDEO_WIDGET (priv->video_preview));
+
+  gst_element_set_state (preview, state);
+  gst_element_set_state (priv->video_input, state);
+  gst_element_set_state (priv->video_tee, state);
 }
 
 static void
@@ -705,8 +735,7 @@ display_video_preview (EmpathyCallWindow *self,
       /* Display the preview and hide the self avatar */
       DEBUG ("Show video preview");
 
-      if (priv->video_preview == NULL)
-        empathy_call_window_setup_video_preview (self);
+      play_camera (self, TRUE);
       gtk_widget_show (priv->video_preview);
       gtk_widget_hide (priv->self_user_avatar_widget);
     }
@@ -717,6 +746,7 @@ display_video_preview (EmpathyCallWindow *self,
 
       if (priv->video_preview != NULL)
         gtk_widget_hide (priv->video_preview);
+      play_camera (self, FALSE);
       gtk_widget_show (priv->self_user_avatar_widget);
     }
 }
@@ -917,6 +947,23 @@ action_camera_change_cb (GtkRadioAction *action,
 }
 
 static void
+create_pipeline (EmpathyCallWindow *self)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (self);
+  GstBus *bus;
+
+  g_assert (priv->pipeline == NULL);
+
+  priv->pipeline = gst_pipeline_new (NULL);
+  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+  priv->bus_message_source_id = gst_bus_add_watch (bus,
+      empathy_call_window_bus_message, self);
+
+  g_object_unref (bus);
+}
+
+
+static void
 empathy_call_window_init (EmpathyCallWindow *self)
 {
   EmpathyCallWindowPriv *priv = GET_PRIV (self);
@@ -925,7 +972,6 @@ empathy_call_window_init (EmpathyCallWindow *self)
   GtkWidget *h;
   GtkWidget *arrow;
   GtkWidget *page;
-  GstBus *bus;
   gchar *filename;
   GKeyFile *keyfile;
   GError *error = NULL;
@@ -972,14 +1018,50 @@ empathy_call_window_init (EmpathyCallWindow *self)
                                   CONTENT_HBOX_BORDER_WIDTH);
   gtk_paned_pack1 (GTK_PANED (priv->pane), priv->content_hbox, TRUE, FALSE);
 
-  priv->pipeline = gst_pipeline_new (NULL);
-  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
-  priv->bus_message_source_id = gst_bus_add_watch (bus,
-      empathy_call_window_bus_message, self);
+  /* remote user output frame */
+  priv->remote_user_output_frame = gtk_frame_new (NULL);
+  gtk_widget_set_size_request (priv->remote_user_output_frame,
+      EMPATHY_VIDEO_WIDGET_DEFAULT_WIDTH, EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT);
+  gtk_box_pack_start (GTK_BOX (priv->content_hbox),
+      priv->remote_user_output_frame, TRUE, TRUE,
+      CONTENT_HBOX_CHILDREN_PACKING_PADDING);
+
+  priv->remote_user_output_hbox = gtk_hbox_new (FALSE, 0);
+
+  priv->remote_user_avatar_widget = gtk_image_new ();
+
+  gtk_box_pack_start (GTK_BOX (priv->remote_user_output_hbox),
+      priv->remote_user_avatar_widget, TRUE, TRUE, 0);
+
+  gtk_container_add (GTK_CONTAINER (priv->remote_user_output_frame),
+      priv->remote_user_output_hbox);
+
+  /* self user output frame */
+  priv->self_user_output_frame = gtk_frame_new (NULL);
+  gtk_widget_set_size_request (priv->self_user_output_frame,
+      SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH);
+
+  priv->self_user_output_hbox = gtk_hbox_new (FALSE, 0);
+
+  priv->self_user_avatar_widget = gtk_image_new ();
+  gtk_box_pack_start (GTK_BOX (priv->self_user_output_hbox),
+      priv->self_user_avatar_widget, TRUE, TRUE, 0);
+
+  gtk_container_add (GTK_CONTAINER (priv->self_user_output_frame),
+      priv->self_user_output_hbox);
+
+  create_pipeline (self);
+  create_video_output_widget (self);
+  create_audio_input (self);
+  create_audio_output (self);
+  create_video_input (self);
 
   priv->fsnotifier = fs_element_added_notifier_new ();
   fs_element_added_notifier_add (priv->fsnotifier, GST_BIN (priv->pipeline));
 
+  /* The call will be started as soon the pipeline is playing */
+  priv->start_call_when_playing = TRUE;
+
   keyfile = g_key_file_new ();
   filename = empathy_file_lookup ("element-properties", "data");
   if (g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error))
@@ -995,30 +1077,14 @@ empathy_call_window_init (EmpathyCallWindow *self)
     }
   g_free (filename);
 
-
-  priv->remote_user_output_frame = gtk_frame_new (NULL);
-  gtk_widget_set_size_request (priv->remote_user_output_frame,
-      EMPATHY_VIDEO_WIDGET_DEFAULT_WIDTH, EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT);
-  gtk_box_pack_start (GTK_BOX (priv->content_hbox),
-      priv->remote_user_output_frame, TRUE, TRUE,
-      CONTENT_HBOX_CHILDREN_PACKING_PADDING);
-  empathy_call_window_setup_remote_frame (bus, self);
-
-  priv->self_user_output_frame = gtk_frame_new (NULL);
-  gtk_widget_set_size_request (priv->self_user_output_frame,
-      SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH);
-
   priv->vbox = gtk_vbox_new (FALSE, 3);
   gtk_box_pack_start (GTK_BOX (priv->content_hbox), priv->vbox,
       FALSE, FALSE, CONTENT_HBOX_CHILDREN_PACKING_PADDING);
   gtk_box_pack_start (GTK_BOX (priv->vbox), priv->self_user_output_frame,
       FALSE, FALSE, 0);
-  empathy_call_window_setup_self_frame (bus, self);
 
   empathy_call_window_setup_toolbar (self);
 
-  g_object_unref (bus);
-
   priv->sidebar_button = gtk_toggle_button_new_with_mnemonic (_("_Sidebar"));
   arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
   g_signal_connect (G_OBJECT (priv->sidebar_button), "toggled",
@@ -1443,10 +1509,10 @@ empathy_call_window_request_resource_cb (EmpathyCallHandler *handler,
 }
 
 static gboolean
-empathy_call_window_reset_pipeline (EmpathyCallWindow *self)
+destroy_pipeline (EmpathyCallWindow *self)
 {
-  GstStateChangeReturn state_change_return;
   EmpathyCallWindowPriv *priv = GET_PRIV (self);
+  GstStateChangeReturn state_change_return;
 
   if (priv->pipeline == NULL)
     return TRUE;
@@ -1459,48 +1525,53 @@ empathy_call_window_reset_pipeline (EmpathyCallWindow *self)
 
   state_change_return = gst_element_set_state (priv->pipeline, GST_STATE_NULL);
 
-  if (state_change_return == GST_STATE_CHANGE_SUCCESS ||
-        state_change_return == GST_STATE_CHANGE_NO_PREROLL)
-    {
-      if (priv->pipeline != NULL)
-        g_object_unref (priv->pipeline);
-      priv->pipeline = NULL;
+  if (state_change_return != GST_STATE_CHANGE_SUCCESS &&
+      state_change_return != GST_STATE_CHANGE_NO_PREROLL)
+    return FALSE;
+
+  if (priv->pipeline != NULL)
+    g_object_unref (priv->pipeline);
+  priv->pipeline = NULL;
 
-      if (priv->video_input != NULL)
-        g_object_unref (priv->video_input);
-      priv->video_input = NULL;
+  g_signal_handlers_disconnect_by_func (priv->audio_input_adj,
 
-      if (priv->audio_input != NULL)
-        g_object_unref (priv->audio_input);
-      priv->audio_input = NULL;
+  empathy_call_window_mic_volume_changed_cb, self);
 
-      g_signal_handlers_disconnect_by_func (priv->audio_input_adj,
-          empathy_call_window_mic_volume_changed_cb, self);
+  if (priv->video_tee != NULL)
+    g_object_unref (priv->video_tee);
+  priv->video_tee = NULL;
 
-      if (priv->audio_output != NULL)
-        g_object_unref (priv->audio_output);
-      priv->audio_output = NULL;
+  if (priv->video_preview != NULL)
+    gtk_widget_destroy (priv->video_preview);
+  priv->video_preview = NULL;
 
-      if (priv->video_tee != NULL)
-        g_object_unref (priv->video_tee);
-      priv->video_tee = NULL;
+  priv->liveadder = NULL;
+  priv->funnel = NULL;
 
-      if (priv->video_preview != NULL)
-        gtk_widget_destroy (priv->video_preview);
-      priv->video_preview = NULL;
+  return TRUE;
+}
 
-      priv->liveadder = NULL;
-      priv->funnel = NULL;
+static gboolean
+empathy_call_window_reset_pipeline (EmpathyCallWindow *self)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (self);
 
-      return TRUE;
-    }
-  else
+  if (priv->pipeline == NULL)
+    return TRUE;
+
+  if (!destroy_pipeline (self))
     {
       g_message ("Error: could not destroy pipeline. Closing call window");
       gtk_widget_destroy (GTK_WIDGET (self));
-
       return FALSE;
     }
+
+  create_pipeline (self);
+  /* Call will be started when user will hit the 'redial' button */
+  priv->start_call_when_playing = FALSE;
+  gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+
+  return TRUE;
 }
 
 static gboolean
@@ -1533,35 +1604,39 @@ empathy_call_window_disconnected (EmpathyCallWindow *self)
       gtk_action_set_sensitive (priv->redial, TRUE);
       gtk_widget_set_sensitive (priv->redial_button, TRUE);
 
-      /* Reseting the send_video, camera_buton and mic_button to their
-         initial state */
+      /* Unsensitive the camera and mic button */
       gtk_widget_set_sensitive (priv->tool_button_camera_on, FALSE);
       gtk_widget_set_sensitive (priv->mic_button, FALSE);
-      gtk_toggle_tool_button_set_active (
-          GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_off), TRUE);
+
+      /* Be sure that the mic button is enabled */
       gtk_toggle_tool_button_set_active (
           GTK_TOGGLE_TOOL_BUTTON (priv->mic_button), TRUE);
 
-      /* FIXME: This is to workaround the fact that the pipeline has been
-       * destroyed and so we can't display preview until a new call (and so a
-       * new pipeline) is created. We should fix this properly by refactoring
-       * the code managing the pipeline. This is bug #602937 */
-      gtk_widget_set_sensitive (priv->tool_button_camera_preview, FALSE);
-      gtk_action_set_sensitive (priv->action_camera_preview, FALSE);
+      if (priv->camera_state == CAMERA_STATE_ON)
+        {
+          /* Enable the 'preview' button as we are not sending atm. */
+          gtk_toggle_tool_button_set_active (
+              GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_preview), TRUE);
+        }
+      else if (priv->camera_state == CAMERA_STATE_PREVIEW)
+        {
+          /* Restart the preview with the new pipeline. */
+          display_video_preview (self, TRUE);
+        }
 
       gtk_progress_bar_set_fraction (
           GTK_PROGRESS_BAR (priv->volume_progress_bar), 0);
 
-      gtk_widget_hide (priv->video_output);
+      /* destroy the video output; it will be recreated when we'll redial */
+      gtk_widget_destroy (priv->video_output);
+      priv->video_output = NULL;
+
       gtk_widget_show (priv->remote_user_avatar_widget);
 
       priv->sending_video = FALSE;
       priv->call_started = FALSE;
 
       could_disconnect = TRUE;
-
-      /* TODO: display the self avatar of the preview (depends if the "Always
-       * Show Video Preview" is enabled or not) */
     }
 
   return could_disconnect;
@@ -1921,11 +1996,6 @@ empathy_call_window_connected (gpointer user_data)
 
   gtk_widget_set_sensitive (priv->mic_button, TRUE);
 
-  /* FIXME: this should won't be needed once bug #602937 is fixed
-   * (see empathy_call_window_disconnected for details) */
-  gtk_widget_set_sensitive (priv->tool_button_camera_preview, TRUE);
-  gtk_action_set_sensitive (priv->action_camera_preview, TRUE);
-
   empathy_call_window_update_avatars_visibility (call, self);
 
   g_object_unref (call);
@@ -2055,7 +2125,6 @@ start_call (EmpathyCallWindow *self)
 
   priv->call_started = TRUE;
   empathy_call_handler_start_call (priv->handler);
-  gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
 
   if (empathy_call_handler_has_initial_video (priv->handler))
     {
@@ -2090,7 +2159,10 @@ empathy_call_window_bus_message (GstBus *bus, GstMessage *message,
             gst_message_parse_state_changed (message, NULL, &newstate, NULL);
             if (newstate == GST_STATE_PAUSED)
               {
-                start_call (self);
+                gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+
+                if (priv->start_call_when_playing)
+                  start_call (self);
               }
           }
         break;
@@ -2400,9 +2472,6 @@ empathy_call_window_mic_toggled_cb (GtkToggleToolButton *toggle,
   EmpathyCallWindowPriv *priv = GET_PRIV (window);
   gboolean active;
 
-  if (priv->audio_input == NULL)
-    return;
-
   active = (gtk_toggle_tool_button_get_active (toggle));
 
   if (active)
@@ -2448,26 +2517,16 @@ static void
 empathy_call_window_hangup_cb (gpointer object,
                                EmpathyCallWindow *window)
 {
-  if (empathy_call_window_disconnected (window))
-    gtk_widget_destroy (GTK_WIDGET (window));
+  destroy_pipeline (window);
+  gtk_widget_destroy (GTK_WIDGET (window));
 }
 
 static void
 empathy_call_window_restart_call (EmpathyCallWindow *window)
 {
-  GstBus *bus;
   EmpathyCallWindowPriv *priv = GET_PRIV (window);
 
-  gtk_widget_destroy (priv->remote_user_output_hbox);
-  gtk_widget_destroy (priv->self_user_output_hbox);
-
-  priv->pipeline = gst_pipeline_new (NULL);
-  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
-  priv->bus_message_source_id = gst_bus_add_watch (bus,
-      empathy_call_window_bus_message, window);
-
-  empathy_call_window_setup_remote_frame (bus, window);
-  empathy_call_window_setup_self_frame (bus, window);
+  create_video_output_widget (window);
 
   g_signal_connect (G_OBJECT (priv->audio_input_adj), "value-changed",
       G_CALLBACK (empathy_call_window_mic_volume_changed_cb), window);
@@ -2477,10 +2536,6 @@ empathy_call_window_restart_call (EmpathyCallWindow *window)
    * been updated during that time. That's why we manually update it here */
   empathy_call_window_mic_volume_changed_cb (priv->audio_input_adj, window);
 
-  g_object_unref (bus);
-
-  gtk_widget_show_all (priv->content_hbox);
-
   priv->outgoing = TRUE;
   empathy_call_window_set_state_connecting (window);
 
