Initial SVN import
[maemo-recorder] / src / maemo-recorder-ui.c
diff --git a/src/maemo-recorder-ui.c b/src/maemo-recorder-ui.c
new file mode 100644 (file)
index 0000000..58d22cd
--- /dev/null
@@ -0,0 +1,1967 @@
+/* vim: set ts=4 sw=4 et: */
+/*
+ * maemo-recorder-ui.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+
+#include <gst/gst.h>
+#include <glib/gi18n-lib.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <locale.h>
+#include <hildon-widgets/hildon-program.h>
+#include <hildon-widgets/hildon-note.h>
+#include <hildon-widgets/hildon-banner.h>
+#include <hildon-widgets/hildon-defines.h>
+#include <hildon-widgets/hildon-file-system-model.h>
+#include <hildon-widgets/hildon-file-chooser-dialog.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "maemo-recorder.h"
+#include "maemo-recorder-ui.h"
+#include "maemo-recorder-file.h"
+
+
+#define DEFAULT_REC_BLOCKSIZE "160"
+
+#define STOP_DELAY 500
+#define REC_UPDATE_INTERVAL 750
+#define PLAY_UPDATE_INTERVAL 200
+
+/* MACROs */
+
+#define GST_TIME_MINS(t) \
+        (guint) ((((GstClockTime)(t)) / (GST_SECOND * 60)) % 60)
+#define GST_TIME_SECS(t) \
+        (guint) ((((GstClockTime)(t)) / GST_SECOND) % 60)
+#define GST_TIME_TO_SECS(t) \
+        (gdouble) (((gdouble)(t)) / (gdouble) GST_SECOND) /* GST_SECOND should be 1e9 */
+#define GST_TIME_MSECS(t) \
+        (guint) (((GstClockTime)(t)) % GST_SECOND)
+
+#define RECORDER_APP_TITLE "Maemo Recorder"
+#define RECORDER_MSG_READY _("Ready")
+#define RECORDER_MSG_STOPPED _("Stopped")
+#define RECORDER_MSG_PAUSED _("Paused")
+#define RECORDER_MSG_PLAYING  _("Playing")
+#define RECORDER_MSG_RECORDING _("Recording")
+#define RECORDER_FILE_UNTITLED _("Untitled")
+
+/* general enumerations */
+    
+typedef enum
+{
+    DTX_OFF = 0,
+    DTX_ON = 1
+} DTX;
+
+/* menu codes */
+typedef enum 
+{
+    MENU_FILE_NEW = 1,
+    MENU_FILE_OPEN,
+    MENU_FILE_SAVE,
+    MENU_FILE_SAVE_AS,
+    MENU_FILE_REC,
+    MENU_FILE_PLAY,
+    MENU_FILE_STOP,
+    MENU_FILE_QUIT
+} MenuActionCode;
+
+typedef enum 
+{
+    PIPELINE_PLAY = 1,
+    PIPELINE_PLAY_MP3,
+    PIPELINE_REC
+} PipeLineType;
+
+/* function prototypes */
+
+static gboolean cbBus (GstBus *bus, 
+               GstMessage *message, 
+               gpointer data);
+
+static void pipelineStateChanged (GstElement *element,
+                  GstState old,
+                  GstState new,
+                  GstState pending,
+                  AppData *data);
+
+static void seekToTime(GstElement *pipeline, gdouble secs);
+static gboolean seekToZero(AppData *data, GstElement *pipeline);
+static void setLength(AppData *data, gdouble secs);
+static gboolean cbStopPlayback(AppData *data);
+static void cbStop(GtkWidget* widget, AppData *data);
+static void cbPlay(GtkWidget* widget, AppData *data);
+static void cbRec(GtkWidget* widget, AppData *data);
+static void cbNew(GtkWidget* widget, AppData *data);
+static void cbOpen(GtkWidget* widget, AppData *data);
+/*static void cbSave(GtkWidget* widget, AppData *data);*/
+static void cbSaveAs(GtkWidget* widget, AppData *data);
+static void cbItemClose(GtkWidget *widget, gpointer data);
+static void cbUserSeek(GtkAdjustment *adjustment, gpointer data);
+static gchar* cbFormatSeekbarValue(GtkScale *scale, gdouble value);
+static GtkWidget* createToolBar(AppData *data);
+static void createMenu( AppData *data );
+static gboolean createPipeline(AppData *app, PipeLineType type);
+static void openPlayPipeline( AppData *data );
+static gboolean destroyPipeline(AppData *data, PipeLineType type);
+static gboolean destroyPipelines(AppData *data);
+static void cbItemGroupChanged(gpointer data);
+static gboolean cbUpdateRecLength(AppData *data);
+static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data);
+static gboolean openURI(gpointer user_data);
+static gboolean closeFile(AppData *data);
+static gdouble guessMediaLength(AppData *data);
+static GstCaps *createCapsFilter(AudioFormat format);
+
+static void new_pad_cb (GstElement *wavparse, GstPad *new_pad, gpointer data)
+{
+    GstElement *sink;
+    AppData* app = (AppData*) data; 
+
+    ULOG_INFO("new pad");
+    sink = gst_element_factory_make ("dsppcmsink", "sink");
+    gst_bin_add (GST_BIN (app->playPipeline), sink);
+    if (!gst_element_link (wavparse, sink))
+      g_error ("link(wavparse, sink) failed!");
+    gst_element_sync_state_with_parent(sink); 
+}
+
+static gboolean createPipeline(AppData *app, PipeLineType type)
+{
+    GstElement *src = NULL;
+    GstElement *sink = NULL;
+    GstElement *filter = NULL;
+    GstElement *queue = NULL;
+    GstElement *pipeline = NULL;
+    GstElement *parse = NULL;
+    GstCaps *caps = NULL;
+
+    g_assert(NULL != app);
+
+    pipeline = gst_pipeline_new("pipeline");
+
+    gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
+                   cbBus, app);
+
+    /* create elements */
+    switch (type)
+    {
+        case PIPELINE_PLAY_MP3:
+            ULOG_INFO("mp3 playback - queue");
+            src = gst_element_factory_make ("filesrc", "source");
+            queue = gst_element_factory_make ("queue", "queue");
+            sink = gst_element_factory_make ("dspmp3sink", "sink");
+
+            g_object_set(G_OBJECT (queue), 
+                "max-size-buffers", 8192,
+                "min-threshold-bytes", 131072,
+                "min-threshold-buffers", 2048,
+                NULL );
+            g_object_set(G_OBJECT(src), 
+                    "location", app->openFileName, 
+                    NULL);
+            break;
+
+        case PIPELINE_PLAY:
+            src = gst_element_factory_make ("filesrc", "source");
+            /* we need also a filter to modify caps */
+            filter = gst_element_factory_make("capsfilter", "filter");
+            switch (app->filter)
+            {
+                case FORMAT_ILBC:
+                    ULOG_INFO("using ilbc sink");
+                    sink = gst_element_factory_make ("dspilbcsink", "sink");
+                    break;
+
+                case FORMAT_PCMA:
+                case FORMAT_PCMU:
+                case FORMAT_PCM:
+                    ULOG_INFO("using pcm sink");
+                    sink = gst_element_factory_make ("dsppcmsink", "sink");
+                    break;
+
+                case FORMAT_WAV:
+                    ULOG_INFO("using wavparse & pcm sink");
+                    parse = gst_element_factory_make ("wavparse", "parse");
+                    break;
+                    
+                default:
+                    break;  
+            }
+
+            g_object_set(G_OBJECT(src), 
+                    "location", app->openFileName, 
+                    NULL);
+
+            caps = createCapsFilter(app->filter);
+            g_object_set(G_OBJECT(filter), 
+                  "caps", caps,
+                  NULL);
+            break;
+
+        case PIPELINE_REC:
+            switch (app->filter)  
+            {    
+                case FORMAT_ILBC:
+                    ULOG_INFO("using ilbc source");
+                    src = gst_element_factory_make("dspilbcsrc", "source");
+                    g_object_set(G_OBJECT(src),
+                        "dtx", DTX_OFF,
+                        NULL);
+                    break;
+        
+                case FORMAT_PCMA:
+                case FORMAT_PCMU:
+                case FORMAT_PCM:
+                    ULOG_INFO("using pcm source");
+                    src = gst_element_factory_make("dsppcmsrc", "source");
+                    g_object_set(G_OBJECT (src), 
+                          "blocksize", DEFAULT_REC_BLOCKSIZE, 
+                          "dtx", DTX_OFF,
+                        NULL);
+                    break;
+            
+                case FORMAT_WAV:
+                    ULOG_INFO("using pcm source & wavenc");
+                    src = gst_element_factory_make("dsppcmsrc", "source");
+                    g_object_set(G_OBJECT (src),
+                            "blocksize", DEFAULT_REC_BLOCKSIZE,
+                            "dtx", DTX_OFF,
+                            NULL);
+                    parse = gst_element_factory_make("wavenc", "enc");
+                    break;   
+            
+                default:
+                    ULOG_WARN("Unknown filter type!");
+                    break; 
+            }
+
+            filter = gst_element_factory_make("capsfilter", "filter");
+            caps = createCapsFilter(app->filter);
+            g_object_set(G_OBJECT(filter), 
+                  "caps", caps,
+                  NULL);
+
+            sink = gst_element_factory_make("filesink", "sink");
+
+            g_object_set(G_OBJECT(sink), 
+                "location", app->saveFileName,
+                NULL);
+            break;
+
+        default:
+            ULOG_ERR("Invalid pipeline type!");
+            gst_object_unref(pipeline);
+            return FALSE;
+    }
+
+    if (!src || !pipeline)
+    {
+        ULOG_ERR("Could not create GstElement!");
+        return FALSE;
+    }
+
+    if (!sink && app->filter != FORMAT_WAV)
+    {
+        ULOG_ERR("Could not create GstElement!");
+        return FALSE;        
+    }
+        
+    ULOG_INFO("Create pipeline");
+     
+    /* add to pipeline and link */
+    switch (type)
+    {
+        case PIPELINE_REC:
+          switch (app->filter)
+           {
+            case FORMAT_ILBC:
+            case FORMAT_PCM:
+            case FORMAT_PCMA:
+                if (!filter)
+                {
+                   ULOG_ERR("Could not create filter GstElement!");
+                   return FALSE;
+                }
+                gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
+
+                if (!gst_element_link_many (src, filter, sink, NULL))
+                {
+                    ULOG_ERR("gst_element_link failed for src, filter and sink!");
+                    return FALSE;
+                }
+                break;   
+            case FORMAT_WAV:
+                gst_bin_add_many(GST_BIN(pipeline), src, parse, sink, NULL);
+                if (!gst_element_link_many (src, parse, sink, NULL))
+                {
+                    ULOG_ERR("gst_element_link failed for src, parse and sink!");
+                }
+                break;
+     
+            default:
+                break;
+          
+         }
+         break; 
+        
+        case PIPELINE_PLAY:
+          switch (app->filter)
+           {
+            case FORMAT_ILBC:
+            case FORMAT_PCM:
+            case FORMAT_PCMA:
+                if (!filter)
+                {
+                   ULOG_ERR("Could not create filter GstElement!");
+                   return FALSE;
+                }
+                gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
+
+                if (!gst_element_link_many (src, filter, sink, NULL))
+                {
+                    ULOG_ERR("gst_element_link failed for src, filter and sink!");
+                    return FALSE;
+                }
+
+                break;
+            case FORMAT_WAV:
+                gst_bin_add_many(GST_BIN(pipeline), src, parse, NULL);
+                if (!gst_element_link_many (src, parse, NULL))
+                {
+                    ULOG_ERR("gst_element_link failed for src, parse and sink!");
+                    return FALSE;
+                }
+                app->playPipeline = pipeline;
+                g_signal_connect(parse, "pad_added",
+                             G_CALLBACK(new_pad_cb), app);
+         
+                break;
+
+            default:
+                break;
+           }
+
+           break;
+     
+        case PIPELINE_PLAY_MP3:
+        default:
+            gst_bin_add_many(GST_BIN(pipeline), src, queue, sink, NULL);
+            if(!gst_element_link_many(src, queue, sink, NULL))
+            {
+                 ULOG_ERR("gst_element_link failed for src and sink!");
+                 return FALSE;
+            }
+
+            break;
+    }
+
+    /* set application data */
+    if (type == PIPELINE_REC)
+    {
+        app->recPipeline = pipeline;
+    }
+    else
+    {
+        app->playPipeline = pipeline;
+        app->playPipelineType = type;
+    }
+     
+    if (caps)
+    {
+        gst_caps_unref(caps);
+        caps = NULL;
+    }
+
+    return TRUE;
+}
+
+static gboolean destroyPipelines(AppData *data)
+{
+    gboolean ret = FALSE;
+
+    /* ugly hack with pipeline types, but works though */
+    ret != destroyPipeline(data, PIPELINE_REC);
+    ret != destroyPipeline(data, PIPELINE_PLAY);
+    return ret;
+}
+
+static gboolean destroyPipeline(AppData *data, PipeLineType type)
+{
+     GstState state;
+     GstState pending;
+     GstElement *pipeline = NULL;
+
+     ULOG_INFO("%s() - Stopping playback/recording", G_STRFUNC);
+
+     switch (type)
+     {
+        case PIPELINE_REC:
+            pipeline = data->recPipeline;
+            /*
+            data->recPipeline = NULL;
+            */
+            break;
+        default:
+            pipeline = data->playPipeline;
+            /*
+            data->playPipeline = NULL;
+            */
+            break;
+     }
+    
+     if (!GST_IS_ELEMENT(pipeline))
+         return TRUE;
+
+     /* this unallocates everything */
+     gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
+
+     /* for some reason the state does not update manually */
+     gst_element_get_state(pipeline, &state, 
+                &pending, GST_CLOCK_TIME_NONE);
+     pipelineStateChanged(pipeline,
+               state,
+               state,
+               pending,
+               data);
+
+     /*
+     gst_object_unref(pipeline);
+     */
+
+     return TRUE;
+}
+
+
+/* callbacks */
+
+static void pipelineStateChanged (GstElement *element,
+                  GstState old,
+                  GstState new,
+                  GstState pending,
+                  AppData * data)
+{
+    g_assert(NULL != data);
+     
+    switch (new)
+    {
+        case GST_STATE_PLAYING:
+          if(APPSTATE_RECORDING == getAppState(data))
+          {
+               gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_RECORDING);
+               hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
+               g_free(tmp);
+               tmp = NULL;
+               ULOG_INFO("%s() - Recording", G_STRFUNC);
+               gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry), 
+                      RECORDER_MSG_RECORDING);
+
+               gtk_widget_set_state(data->buttonRec, GTK_STATE_ACTIVE);
+
+               if (data->recUpdateId == 0 && gettimeofday(&data->recStartTv, NULL) == 0)
+               {
+                   data->recUpdateId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, REC_UPDATE_INTERVAL, (GSourceFunc) cbUpdateRecLength, data, NULL);
+               }
+          }
+          else
+          {
+               gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_PLAYING);
+               hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
+               g_free(tmp);
+               tmp = NULL;
+               ULOG_INFO("%s() - Playing", G_STRFUNC);
+               gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry), 
+                      RECORDER_MSG_PLAYING);  
+               gtk_widget_set_state(data->buttonPlay, GTK_STATE_ACTIVE);
+               /*
+               gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PAUSE);
+               */
+          }
+
+          break;
+
+        case GST_STATE_READY:
+          //hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, "Ready...");
+          ULOG_INFO("%s() - Ready", G_STRFUNC);
+          gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry), 
+                     RECORDER_MSG_READY);  
+          break;
+
+        case GST_STATE_PAUSED:
+          {
+              gint64 pos = 0;
+              GstFormat fmt = GST_FORMAT_TIME;
+              ULOG_INFO("%s() - Paused", G_STRFUNC);
+
+              /* if pipeline pos == 0 => stopped, else => paused */
+              if (GST_IS_ELEMENT(data->playPipeline) && gst_element_query_position(data->playPipeline, &fmt, &pos) && pos != 0)
+              {
+                  hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_PAUSED);       
+                  gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry), 
+                         RECORDER_MSG_PAUSED);
+                  /*
+                  gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
+                  gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
+                  */
+              }
+              else
+              {
+                  hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);       
+                  gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry), 
+                         RECORDER_MSG_STOPPED);  
+                  gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
+                  gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
+              }
+              gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
+          }
+          break;
+          
+        case GST_STATE_NULL:
+          ULOG_INFO("%s() - Null", G_STRFUNC);
+          hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
+          gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry), 
+                     RECORDER_MSG_READY);  
+          gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
+          gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
+          gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
+          
+          break;
+
+        default:
+          ULOG_WARN("%s() - default case", G_STRFUNC);
+          break;
+    }
+}
+
+
+static gboolean cbBus(GstBus *bus,
+               GstMessage *message,
+               gpointer   data)
+{
+     AppData *app = (AppData*)data;
+
+     switch (GST_MESSAGE_TYPE(message)) 
+     {
+     case GST_MESSAGE_WARNING:
+     {
+      GError *err;
+      gchar *debug;
+      
+      gst_message_parse_error (message, &err, &debug);
+      ULOG_WARN("%s() - Warning: %s", G_STRFUNC, err->message);
+      g_error_free (err);
+      g_free (debug);
+      break;
+     }
+     case GST_MESSAGE_ERROR: 
+     {
+      GError *err;
+      gchar *debug;
+      
+      gst_message_parse_error (message, &err, &debug);
+      ULOG_ERR("%s() - Error: %s", G_STRFUNC, err->message);
+      g_error_free (err);
+      g_free (debug);
+      /* break; */
+      /* flow through to eos */
+     }
+     case GST_MESSAGE_EOS:
+     {
+        ULOG_INFO("%s() - eos", G_STRFUNC);
+     
+         switch(getAppState(app))
+         {
+         case APPSTATE_PLAYING:
+              /* stop playback after a short break*/
+              g_timeout_add(STOP_DELAY, (GSourceFunc)cbStopPlayback, data);
+              break;
+
+         case APPSTATE_RECORDING:
+          gst_element_set_state(GST_ELEMENT(app->recPipeline), 
+               GST_STATE_PAUSED);
+          destroyPipeline(app, PIPELINE_REC);
+          app->saved = FALSE;
+          break;
+         case APPSTATE_READY:
+         default:
+             /* destroyPipelines(app); */
+          break;
+         }
+         break;
+     }
+     case GST_MESSAGE_STATE_CHANGED: 
+     {
+      GstState old;
+      GstState new;
+      GstState pending;
+      
+      gst_message_parse_state_changed(message, &old, &new, &pending);
+    
+      pipelineStateChanged(NULL, old, new, pending, app);
+  
+      break;
+     }
+     default:
+      /* unhandled message */
+      ULOG_WARN("%s() - Unhandled message, type = %d", G_STRFUNC, message->type);
+      break;
+     }
+     
+     /* remove message from the queue */
+     return TRUE;
+}
+
+static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data)
+{     
+    AppData* app;
+
+    g_assert(data);
+
+    app = (AppData *) data;
+
+    if (!closeFile(app))
+        return;
+
+    destroyPipelines(app);
+    if (app->playPipeline)
+        gst_object_unref(GST_OBJECT(app->playPipeline));
+
+    if (app->recPipeline)
+        gst_object_unref(GST_OBJECT(app->recPipeline));
+
+    gtk_main_quit();
+}
+
+static gboolean cbCheckPosition (AppData *data)
+{
+     GstFormat fmt = GST_FORMAT_TIME;
+     gint64 pos = 0, len = 0;
+     static gboolean lengthSet = FALSE;
+
+     g_assert(NULL != data);
+
+     /* get length */
+     if(!lengthSet && gst_element_query_duration(data->playPipeline, &fmt, &len))
+     {
+       if (len > 0)
+       {
+          gdouble size = 0;
+          size = GST_TIME_TO_SECS(len);
+          setLength(data, size); /* sets lengthEntry and adjustment */
+          lengthSet = TRUE;
+       }
+     }
+
+     /* calculate position */
+    if (gst_element_query_position(data->playPipeline, &fmt, &pos))
+    {
+        gdouble time = GST_TIME_TO_SECS(pos);
+      
+        ULOG_DEBUG("pos = %lld, time = %f", 
+             pos,
+           time 
+           );
+
+        gtk_adjustment_set_value( 
+           GTK_ADJUSTMENT(data->mainViewData.adjustment),
+           time);
+        gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
+    }
+
+    if (APPSTATE_PLAYING == getAppState(data))
+    {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static void cbNew(GtkWidget* widget, AppData *data) 
+{
+    g_assert(NULL != data);
+
+    if (!closeFile(data))
+        return;
+
+    /* remove pipelines if existing */
+    destroyPipelines(data);
+    ULOG_DEBUG_F("cbNew");
+    /* destroy tmp file */
+
+    /* clear filenames */
+    g_free(data->openFileName);
+    data->openFileName = NULL;
+    g_free(data->saveFileName);
+    data->saveFileName = NULL;
+/*    data->filter = FORMAT_NONE;*/
+    data->file_format = FORMAT_NONE;
+
+    /* update display */
+    gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), 
+        RECORDER_FILE_UNTITLED);
+    setLength(data, 0.0);
+    /* update the display + scale */
+    gtk_adjustment_set_value(GTK_ADJUSTMENT(data->mainViewData.adjustment),
+              0);
+    gtk_widget_set_sensitive(data->buttonSave, FALSE);
+    gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
+    data->saved = TRUE;
+
+    gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
+
+    ULOG_DEBUG_F("cbNew end");
+}
+
+static void cbOpen(GtkWidget* widget, AppData *data) 
+{
+    GtkWidget* dialog = NULL;
+    gchar *tmpfile = NULL;
+    gchar *selected = NULL;
+    AudioFormat format;
+    gchar *basename;
+    gdouble len = -1.0;
+#if 0
+    GtkFileFilter *filter;
+#endif
+
+    ULOG_DEBUG_F("begin");
+    g_assert(NULL != data);
+
+    if (!closeFile(data))
+        return;
+
+#if 0
+    /* create filter */
+    filter = gtk_file_filter_new();
+    gtk_file_filter_add_mime_type(filter, "audio/x-mp3");
+#endif
+
+    g_assert(GTK_IS_WINDOW(data->mainView));
+    /* create dialog */
+    dialog = hildon_file_chooser_dialog_new_with_properties(
+              GTK_WINDOW(data->mainView), 
+              "action", GTK_FILE_CHOOSER_ACTION_OPEN,
+              "file-system-model", NULL,
+              "local-only", TRUE,
+              NULL
+              );
+
+    /* show it */
+    gtk_widget_show_all(dialog);
+
+    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) 
+    {
+        selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+    }
+
+    ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
+
+    if (dialog != NULL && GTK_IS_WIDGET(dialog))
+    {
+        gtk_widget_destroy(dialog);
+        /*
+        ULOG_DEBUG("%s() - dialog destroyed", G_STRFUNC);
+        */
+    }
+
+    if (NULL == selected) /* no file selected */
+        return;
+
+    ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
+
+    if (openFile(selected, &format, &tmpfile))
+    {
+        ULOG_INFO("%s() - openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
+
+        g_assert(tmpfile);
+
+        /* update filenames */
+        basename = g_path_get_basename(selected);
+
+        gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
+        gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
+        g_free(basename);
+
+        g_free(data->openFileName);
+        data->openFileName = tmpfile;
+        data->file_format = format;
+        data->filter = format;
+        g_free(data->saveFileName);
+        data->saveFileName = NULL;
+        gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
+
+        len = guessMediaLength(data);
+        if (len > 0.0)
+            setLength(data, len);
+        else
+            setLength(data, 0.0);
+
+        data->saved = TRUE;
+    }
+    else
+    {
+        ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
+        hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
+    }
+
+    g_free(selected);
+
+    ULOG_DEBUG_F("end");
+}
+
+static gboolean
+openURI(gpointer user_data)
+{
+    AppData *data;
+    GnomeVFSURI *uri;
+    gchar *selected = NULL;
+    AudioFormat format;
+    gchar *tmpfile = NULL;
+    gchar *basename = NULL;
+    gdouble len = -1.0;
+
+    g_assert(user_data);
+    data = (AppData *) user_data;
+
+    if (NULL == data->mimeURI)
+        return FALSE;
+
+    uri = gnome_vfs_uri_new(data->mimeURI);
+    selected = g_strdup(gnome_vfs_uri_get_path(uri));
+
+    gnome_vfs_uri_unref(uri);
+    uri = NULL;
+
+    g_free(data->mimeURI);
+    data->mimeURI = NULL;
+
+    /* TODO: the following is duplicated in cbOpen(), move to a tryOpen() function ? */
+
+    if (NULL == selected)
+        return FALSE;
+
+    ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
+
+    if (openFile(selected, &format, &tmpfile))
+    {
+        ULOG_INFO("%s: openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
+
+        g_assert(tmpfile);
+
+        /* update filenames */
+        basename = g_path_get_basename(selected);
+        
+        gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
+        gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
+        g_free(basename);
+
+        g_free(data->openFileName);
+        data->openFileName = tmpfile;
+        data->file_format = format;
+        data->filter = format;
+        g_free(data->saveFileName);
+        data->saveFileName = NULL;
+        gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
+        
+        len = guessMediaLength(data);
+        if (len > 0.0)
+            setLength(data, len);
+        else
+            setLength(data, 0.0);
+
+        data->saved = TRUE;
+    }
+    else
+    {
+        ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
+        hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
+    }
+
+    g_free(selected);
+
+    return FALSE;
+}
+
+static void openPlayPipeline( AppData *data )
+{
+
+    GstFormat fmt = GST_FORMAT_TIME;
+      gint64 len;
+      gdouble size = 0;
+      /* create pipelines */
+      /* check file type */
+      switch (data->file_format)
+      {
+          case FORMAT_PCMA:
+          case FORMAT_PCMU:
+          case FORMAT_PCM:
+          case FORMAT_ILBC:
+          case FORMAT_WAV:
+              destroyPipelines(data);
+              data->filter = data->file_format;
+              createPipeline(data, PIPELINE_PLAY);
+              break;
+          case FORMAT_MP3:
+              destroyPipelines(data);
+              data->filter = data->file_format;
+              createPipeline(data, PIPELINE_PLAY_MP3);
+              break;
+          case FORMAT_NONE:
+          default:
+              ULOG_WARN("%s() - unknown file_format", G_STRFUNC);
+              hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Unknown filetype!"));
+              return;
+
+              break;
+      }
+      
+      if (!GST_IS_ELEMENT(data->playPipeline))
+      {
+          hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline!"));
+          return;
+      }
+
+    gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_READY);
+    gst_element_get_state(GST_ELEMENT(data->playPipeline), NULL, NULL, GST_CLOCK_TIME_NONE /* or ns */);
+
+    /* calculate length */
+    if (gst_element_query_duration (data->playPipeline, &fmt, &len))
+    {
+        if (len > 0)
+        {
+            size = GST_TIME_TO_SECS(len);
+            ULOG_INFO("playSize: len:%lld size:%f", len, size);
+            setLength(data, size);
+        }
+    }
+    /*
+    else 
+    {
+        ULOG_INFO("playSize else");
+        setLength(data, 0.0);
+    }
+    */
+}
+
+/* returns whether the action can proceed or should be aborted */
+static gboolean 
+closeFile(AppData *data)
+{
+    GtkWidget *note;
+    gint i;
+
+    if (data->saved)
+        return TRUE;
+
+    note = hildon_note_new_confirmation_add_buttons(GTK_WINDOW(data->mainView), _("Save recording?"),
+            _("Yes"), GTK_RESPONSE_YES,
+            _("No"), GTK_RESPONSE_NO,
+            _("Cancel"), GTK_RESPONSE_CANCEL,
+            NULL);
+
+    i = gtk_dialog_run(GTK_DIALOG(note));
+    gtk_widget_destroy(note);
+
+    switch (i)
+    {
+        case GTK_RESPONSE_CANCEL:
+            return FALSE;
+
+        case GTK_RESPONSE_NO:
+            return TRUE;
+
+        case GTK_RESPONSE_YES:
+        {
+            cbSaveAs(NULL, data);
+            return data->saved;
+        }
+        default:
+            ULOG_WARN("%s(): unknown response from dialog: %d", G_STRFUNC, i);
+    }
+    return FALSE;
+}
+     
+#if 0
+static void cbSave(GtkWidget* widget, AppData *data) 
+{
+     GtkWidget* dialog = NULL;
+     const gchar *current;
+     gchar *selected = NULL;
+
+     g_assert(data);
+
+     ULOG_DEBUG("%s() - begin", G_STRFUNC);
+
+     current = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
+     if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0) 
+     {
+       hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
+       return;
+     }
+
+     /* if saveFileName does not exist run saveas */
+     if (NULL == data->saveFileName)
+     {
+      /* create dialog */
+      dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
+                   GTK_WINDOW(data->mainView), 
+                   GTK_FILE_CHOOSER_ACTION_SAVE));
+      
+      /* show it */
+      gtk_widget_show_all(dialog);
+      
+      if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) 
+      {
+           selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+      }
+     
+      ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
+      
+      gtk_widget_destroy(dialog);
+      
+      if (NULL != selected)
+      {
+           ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC,
+            selected);
+           g_free(data->saveFileName);
+           data->saveFileName = g_strdup_printf("%s%s", selected, getExtension(data->file_format));
+           g_free(selected);
+           selected = NULL;
+      }
+      else
+      {
+           return;
+      }
+     }
+
+     /* save the file */
+     if (doSave(gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry)), data->saveFileName, data->file_format))
+     {
+      gchar *basename = g_path_get_basename(data->saveFileName);
+      ULOG_INFO("%s() - file succesfully saved!", G_STRFUNC);
+      g_free(data->openFileName);
+      data->openFileName = g_strdup(data->saveFileName);
+            
+      gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), 
+                 data->saveFileName);
+      gtk_widget_set_sensitive(data->buttonSave, FALSE);
+      gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
+      g_free(basename);
+     }
+     
+     ULOG_DEBUG("%s() - end", G_STRFUNC);
+}
+#endif
+
+static void cbSaveAs(GtkWidget* widget, AppData *data) 
+{
+    GtkWidget* dialog = NULL;
+    const gchar *current;
+    gchar *selected = NULL;
+
+    g_assert(NULL != data);
+
+    ULOG_DEBUG("%s() - begin", G_STRFUNC);
+
+    current = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
+    if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0) 
+    {
+        hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
+        return;
+    }
+
+    /* create dialog */
+    dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
+              GTK_WINDOW(data->mainView), 
+              GTK_FILE_CHOOSER_ACTION_SAVE));
+
+    /* show it */
+    gtk_widget_show_all(dialog);
+
+    if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) 
+    {
+        selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+    }
+
+    ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
+    gtk_widget_destroy(dialog);
+
+    if (NULL == selected)
+        return;
+
+    ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
+
+    g_free(data->saveFileName);
+    data->saveFileName = NULL;
+
+    if (saveFile(selected, data->openFileName, data->file_format, &(data->saveFileName)))
+    {
+        gchar *basename;
+        const gchar *ext;
+
+        g_assert(data->saveFileName);
+
+        /* set new title that has the file name */
+        basename = g_path_get_basename(data->saveFileName);
+        ULOG_DEBUG("%s() - file '%s' succesfully saved!", G_STRFUNC, data->saveFileName);
+
+        gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
+
+        /* Houston, we have a kludge:
+         * for AU files we need to keep the old tmpfile for playback
+         * for RAW/iLBC files, we can remove the tmpfile and point openFileName to the saved file
+         */
+        ext = getExtension(data->file_format);
+        if (strcmp(ext, EXTENSION_AU) != 0)
+        {
+            g_free(data->openFileName);
+            data->openFileName = g_strdup(data->saveFileName);
+        }
+
+        gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), 
+                 data->saveFileName);
+        
+        g_free(basename);
+        data->saved = TRUE;
+    }
+    else
+    {
+        hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Saving file failed!"));
+    }
+
+    g_free(selected);
+    selected = NULL;
+
+    ULOG_DEBUG("%s() - end", G_STRFUNC);
+}
+
+static void cbRec(GtkWidget* widget, AppData *data) 
+{
+     g_assert(NULL != data);
+
+     ULOG_DEBUG("%s() - begin", G_STRFUNC);     
+
+     if (APPSTATE_READY != getAppState(data))
+     {
+      ULOG_WARN("%s() - state different than READY -> return", G_STRFUNC);
+      return;
+     }
+
+     if (!closeFile(data))
+         return;
+
+     /* clear filenames, use tmp file */
+     g_free(data->openFileName);
+     data->openFileName = NULL;
+
+     g_free(data->saveFileName);
+     data->saveFileName = NULL;     
+    
+     switch (data->filter)
+     {
+         case FORMAT_PCM:
+             data->saveFileName = g_strdup(DEFAULT_TMP_FILE);
+             data->openFileName = g_strdup(DEFAULT_TMP_FILE);
+             break;
+
+         case FORMAT_PCMA:
+             data->saveFileName = g_strdup(DEFAULT_TMP_PCMA_FILE);
+             data->openFileName = g_strdup(DEFAULT_TMP_PCMA_FILE);
+             break;
+             
+         case FORMAT_PCMU:
+             data->saveFileName = g_strdup(DEFAULT_TMP_PCMU_FILE);
+             data->openFileName = g_strdup(DEFAULT_TMP_PCMU_FILE);
+             break;
+
+         case FORMAT_WAV:
+             data->saveFileName = g_strdup(DEFAULT_TMP_WAV_FILE);
+             data->openFileName = g_strdup(DEFAULT_TMP_WAV_FILE);
+             break;
+
+         case FORMAT_ILBC:
+         default:
+             data->saveFileName = g_strdup(DEFAULT_TMP_ILBC_FILE);
+             data->openFileName = g_strdup(DEFAULT_TMP_ILBC_FILE);
+             break;
+     }
+     
+     ULOG_INFO("%s() - creating pipelines", G_STRFUNC);
+     /* start recording */
+     /* create related pipelines */
+     if (createPipeline(data, PIPELINE_REC))
+     {
+         ULOG_INFO("%s() - starting recording", G_STRFUNC);
+         /* start recording */
+         gst_element_set_state(GST_ELEMENT(data->recPipeline), 
+                               GST_STATE_PLAYING);
+
+         /* update display */
+         gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), 
+                data->saveFileName);
+
+         setAppState(data, APPSTATE_RECORDING);
+         gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
+         gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
+         data->file_format = data->filter;
+     }
+     else
+     {
+       ULOG_ERR("Could not create rec pipeline!");
+       hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline"));
+       setAppState(data, APPSTATE_READY);
+     }
+     
+     ULOG_DEBUG("%s() - end", G_STRFUNC);     
+}
+
+static void cbPlay(GtkWidget* widget, AppData *data) 
+{
+    const gchar * file = NULL;
+     
+    g_assert(NULL != data);
+
+    ULOG_DEBUG("%s() - begin", G_STRFUNC);
+
+    file = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
+    if (NULL == data->openFileName || NULL == file || strcmp(file, RECORDER_FILE_UNTITLED) == 0) 
+    {
+        ULOG_WARN("%s() - nothing to play", G_STRFUNC);
+        return;
+    }
+
+    openPlayPipeline(data);
+     
+    if (APPSTATE_PLAYING == getAppState(data))
+    {
+         if (GST_IS_ELEMENT(data->playPipeline)) 
+         {
+             gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_PAUSED);
+             setAppState(data, APPSTATE_READY);
+         }
+         return;
+    }
+
+    if (APPSTATE_READY != getAppState(data))
+    {
+        ULOG_WARN("%s() - state different than PLAYING or READY -> return", G_STRFUNC);
+        return;
+    }
+
+    ULOG_INFO("filename %s", file);
+     
+    /*openPlayPipeline( data );*/
+     
+    /*if ( ! GST_IS_ELEMENT(data->playPipeline) ) 
+    {
+        if (g_strrstr(data->openFileName, EXTENSION_RAW))
+        {
+             ULOG_INFO("cbOpen() - file was raw, assuming audio/x-raw-int, 8kHz, 1 ch, 16-bit");
+             destroyPipelines(data);
+             createPipeline(data, PIPELINE_PLAY);      
+        }
+    }*/
+     
+    if (! GST_IS_ELEMENT(data->playPipeline))
+    {
+        ULOG_WARN("%s() - playPipeline does not exist", G_STRFUNC);
+        return;
+    }
+
+    gst_element_set_state(GST_ELEMENT(data->playPipeline), 
+               GST_STATE_PLAYING);
+
+    setAppState(data, APPSTATE_PLAYING);
+
+    g_timeout_add(PLAY_UPDATE_INTERVAL, (GSourceFunc)cbCheckPosition, data);
+
+    ULOG_DEBUG("%s() - end", G_STRFUNC);
+}
+
+static void cbStop(GtkWidget* widget, AppData *data) 
+{
+    g_assert(NULL != data);
+
+    ULOG_DEBUG("%s() - begin", G_STRFUNC); 
+
+    /* check if we are playing/recording */
+
+    /*
+    if (APPSTATE_PLAYING != getAppState(data) &&
+    APPSTATE_RECORDING != getAppState(data))
+    {
+      ULOG_WARN("cbStop() - state different than PLAYING or RECORDING "
+          "-> return");
+      return;
+    } 
+    */
+
+    /* stop playing or recording */
+    gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
+    gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
+    gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
+
+    /* destroy related pipeline */
+    switch(getAppState(data))
+    {
+        case APPSTATE_PLAYING:
+            /* don't destroy the playing pipeline. Instead, set the pipeline to PAUSED */
+            /* destroyPipeline(data, PIPELINE_PLAY); */
+            ULOG_INFO("%s() - Setting playPipeline state to PAUSED", G_STRFUNC);
+            gst_element_set_state(GST_ELEMENT(data->playPipeline), 
+                     GST_STATE_PAUSED);
+            /* flow through */
+        case APPSTATE_READY:
+            /* seek to zero, but not for PCM pipeline */
+            /* if (data->playPipelineType == PIPELINE_PLAY || seekToZero(data, GST_ELEMENT(data->playPipeline))) */
+            if ( !GST_IS_ELEMENT(data->playPipeline) || seekToZero(data, GST_ELEMENT(data->playPipeline)))
+            {
+              gtk_adjustment_set_value( 
+                   GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
+              gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
+              gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry), 
+                         RECORDER_MSG_STOPPED);  
+            }
+            break;
+        case APPSTATE_RECORDING:
+        {
+            gdouble len = -1.0;
+            gst_element_set_state(GST_ELEMENT(data->recPipeline), 
+                 GST_STATE_PAUSED);
+            destroyPipeline(data, PIPELINE_REC);
+            gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
+            data->saved = FALSE;
+
+            len = guessMediaLength(data);
+            if (len > 0.0)
+                setLength(data, len);
+
+            break;
+        }
+     
+        default:
+            /* seekToZero(data, GST_ELEMENT(data->playPipeline)); */
+            /* should not come here */
+            break;
+    }
+
+    setAppState(data, APPSTATE_READY);
+
+    ULOG_DEBUG("%s() - end", G_STRFUNC); 
+}
+
+
+/* ui construction functions */
+
+static GtkWidget* createToolBar(AppData *data)
+{
+     GtkToolbar* toolBar = NULL;
+     
+     GtkToolItem* new = NULL;
+     GtkToolItem* open = NULL;
+     GtkToolItem* save = NULL;
+     GtkToolItem* saveas = NULL;
+     GtkToolItem* sep = NULL;
+     GtkToolItem* play = NULL;
+     GtkToolItem* rec = NULL;
+     GtkToolItem* stop = NULL;
+     
+     /* create buttons */
+     new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW); 
+     open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN); 
+     save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
+     data->buttonSave = GTK_WIDGET(save);
+     saveas = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE_AS);
+     data->buttonSaveAs = GTK_WIDGET(saveas);
+     gtk_widget_set_sensitive(data->buttonSave, FALSE);
+     gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
+     data->saved = TRUE;
+
+     rec = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_RECORD); 
+     data->buttonRec = GTK_WIDGET(rec);
+     play = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY); 
+     data->buttonPlay = GTK_WIDGET(play);
+     stop = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
+     
+     /* create separator */
+     sep  = gtk_separator_tool_item_new();
+
+     /* create the toolbar itself */
+     toolBar = GTK_TOOLBAR(gtk_toolbar_new());
+
+     /* add items to toolbar */
+     gtk_toolbar_insert(toolBar, new, -1);
+     gtk_toolbar_insert(toolBar, open, -1);
+     /*
+     gtk_toolbar_insert(toolBar, save, -1);
+     */
+     gtk_toolbar_insert(toolBar, saveas, -1);
+     gtk_toolbar_insert(toolBar, sep,  -1);
+     gtk_toolbar_insert(toolBar, rec, -1);
+     gtk_toolbar_insert(toolBar, play, -1);
+     gtk_toolbar_insert(toolBar, stop, -1);
+
+     /* connect signals */
+     g_signal_connect(G_OBJECT(new), "clicked",
+              G_CALLBACK(cbNew), 
+              data);
+     g_signal_connect(G_OBJECT(open), "clicked",
+              G_CALLBACK(cbOpen), 
+              data);
+     /*
+     g_signal_connect(G_OBJECT(save), "clicked",
+              G_CALLBACK(cbSave), 
+              data);
+     */
+     g_signal_connect(G_OBJECT(saveas), "clicked",
+              G_CALLBACK(cbSaveAs), 
+              data);
+     g_signal_connect(G_OBJECT(rec), "clicked",
+              G_CALLBACK(cbRec), 
+              data);
+     g_signal_connect(G_OBJECT(play), "clicked",
+              G_CALLBACK(cbPlay), 
+              data);
+     g_signal_connect(G_OBJECT(stop), "clicked",
+              G_CALLBACK(cbStop), 
+              data);
+
+     return GTK_WIDGET(toolBar);
+
+}
+
+static void cbItemGroupChanged( gpointer data )
+{
+    AppData* app = (AppData* ) data;
+    GValue active ={G_TYPE_INVALID};
+    gint pcma,ilbc,pcm;
+    
+    g_value_init(&active, G_TYPE_INT);
+
+    g_object_get_property(G_OBJECT(app->radio_pcma), "active", &active);
+    pcma = g_value_get_int(&active);
+    g_object_get_property(G_OBJECT(app->radio_ilbc), "active", &active);
+    ilbc = g_value_get_int(&active);
+    g_object_get_property(G_OBJECT(app->radio_pcm), "active", &active);
+    pcm = g_value_get_int(&active);
+    
+    ULOG_INFO("change type pcma=%d ilbc=%d pcm=%d",pcma, ilbc, pcm);
+    if ( pcma == 1 )
+        app->filter = FORMAT_PCMA;
+    else if ( ilbc == 1 )
+        app->filter = FORMAT_ILBC;
+    else if ( pcm == 1 )
+        app->filter = FORMAT_WAV;
+    else
+        app->filter = -1;
+  
+    ULOG_INFO("filter type=%d", app->filter);
+}
+
+static void cbItemClose(GtkWidget *widget, gpointer data)
+{
+    g_assert(data);
+
+    if (!closeFile(data))
+        return;
+
+    gtk_main_quit();
+}
+
+/* Create the menu items needed for the main view */
+static void createMenu( AppData *data )
+{
+    /* Create needed variables */
+    GSList *group = NULL;
+    GtkMenu *main_menu;
+    GtkWidget *menu_file;
+    GtkWidget *menu_others;
+    GtkWidget *item_file;
+    GtkWidget *item_file_open;
+    GtkWidget *item_file_save_as;
+    GtkWidget *item_others;
+    GtkWidget *item_pcma;
+    GtkWidget *item_pcmu;
+    GtkWidget *item_ilbc;
+    GtkWidget *item_pcm;
+   
+    /*
+    GtkWidget *item_radio_type1;
+    */
+    GtkWidget *item_close;
+    GtkWidget *item_separator;
+
+    /* Get the menu from view */
+    main_menu = GTK_MENU(gtk_menu_new());
+    hildon_window_set_menu(data->mainView, main_menu);
+    
+    /* Create new submenu for "Others" */
+    menu_file = gtk_menu_new ();
+    menu_others = gtk_menu_new ();
+
+    /* Create menu items */
+    item_file = gtk_menu_item_new_with_label (_("File"));
+    item_file_open = gtk_menu_item_new_with_label(_("Open..."));
+    item_file_save_as = gtk_menu_item_new_with_label(_("Save as..."));
+    item_others = gtk_menu_item_new_with_label (_("Recording format"));
+    
+    item_pcma = gtk_radio_menu_item_new_with_label(
+        group, "PCM A-law");
+    item_ilbc = gtk_radio_menu_item_new_with_label_from_widget(
+        GTK_RADIO_MENU_ITEM(item_pcma), "iLBC");
+    item_pcmu = gtk_radio_menu_item_new_with_label_from_widget(
+        GTK_RADIO_MENU_ITEM(item_pcma), "PCM u-law");
+    item_pcm = gtk_radio_menu_item_new_with_label_from_widget(
+        GTK_RADIO_MENU_ITEM(item_pcma), "WAV");
+    
+    /* default is iLBC */
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_ilbc), TRUE); 
+    data->filter = FORMAT_ILBC;
+
+    data->radio_pcma = item_pcma;
+    data->radio_ilbc = item_ilbc;
+    data->radio_pcm = item_pcm;        
+    /*
+    data->radiotype = item_radio_type1;
+    */
+    item_close = gtk_menu_item_new_with_label(_("Close"));
+    item_separator = gtk_separator_menu_item_new();
+    
+    /* Add menu items to right menus */
+    gtk_menu_append( main_menu, item_file );
+    gtk_menu_append( menu_file, item_file_open );
+    gtk_menu_append( menu_file, item_file_save_as );
+    gtk_menu_append( main_menu, item_others );
+    gtk_menu_append( menu_others, item_pcm );
+    gtk_menu_append( menu_others, item_pcma );
+    gtk_menu_append( menu_others, item_ilbc);
+    
+    gtk_menu_append( main_menu, item_close );
+
+    /* Add others submenu to the "Others" item */
+    gtk_menu_item_set_submenu(
+        GTK_MENU_ITEM(item_file), menu_file );
+    gtk_menu_item_set_submenu(
+        GTK_MENU_ITEM(item_others), menu_others );
+
+    /* Attach the callback functions to the activate signal */
+    g_signal_connect( G_OBJECT( item_file_open), "activate",
+        GTK_SIGNAL_FUNC (cbOpen), data);
+    g_signal_connect( G_OBJECT( item_file_save_as), "activate",
+        GTK_SIGNAL_FUNC (cbSaveAs), data);
+    g_signal_connect( G_OBJECT( item_close ), "activate",
+        GTK_SIGNAL_FUNC (cbItemClose), data);
+
+    g_signal_connect_swapped(G_OBJECT(item_pcma), "activate", G_CALLBACK(cbItemGroupChanged), data);
+    g_signal_connect_swapped(G_OBJECT(item_pcm), "activate", G_CALLBACK(cbItemGroupChanged), data);
+    
+    /* Make all menu widgets visible */
+
+    gtk_widget_show_all( GTK_WIDGET( main_menu ) );
+}
+
+gboolean maemo_recorder_ui_new(AppData *data)
+{
+    HildonProgram *app = NULL;
+    HildonWindow *window = NULL;
+    GtkWidget *hbox = NULL;
+    GtkWidget *vbox = NULL;
+    GtkWidget *label = NULL;
+    GtkWidget *entry1 = NULL;
+    GtkWidget *entry2 = NULL;
+    GtkWidget *entry3 = NULL;
+    GtkWidget *toolBar = NULL;
+    GtkWidget *table = NULL;
+    GtkWidget *scale = NULL;
+    GtkObject *adjustment = NULL;
+
+    g_assert(NULL != data);
+
+    app = HILDON_PROGRAM(hildon_program_get_instance());
+    g_set_application_name(RECORDER_APP_TITLE);
+     
+    /* main window */
+    window = HILDON_WINDOW(hildon_window_new());
+
+    hildon_program_add_window(app, window);
+
+    /* content for main view */
+
+    /* create vbox, divides control area and view area */
+    vbox = gtk_vbox_new(FALSE, 0);
+
+    /* create hbox to divide control area */
+    hbox = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
+
+    /* create toolbar */
+    toolBar = createToolBar(data);
+
+    /* create table for labels */
+    table = gtk_table_new (4, 3, FALSE);
+    gtk_table_set_homogeneous(GTK_TABLE(table), FALSE);
+
+    gtk_table_set_row_spacings (GTK_TABLE (table), 4);
+    gtk_table_set_col_spacings (GTK_TABLE (table), 0);
+
+    label = gtk_label_new_with_mnemonic(_("Filename:"));
+    gtk_table_attach_defaults (GTK_TABLE (table),
+            label,
+            0, 1, 0, 1);
+
+    entry1 = gtk_entry_new ();
+    gtk_entry_set_has_frame(GTK_ENTRY(entry1), FALSE);
+    gtk_entry_set_text (GTK_ENTRY (entry1), _(RECORDER_FILE_UNTITLED));
+    gtk_table_attach_defaults (GTK_TABLE (table), entry1, 1, 3, 0, 1);
+    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry1);
+
+    label = gtk_label_new_with_mnemonic (_("Length:"));
+    gtk_table_attach_defaults (GTK_TABLE (table),
+            label,
+            0, 1, 1, 2);
+
+    entry2 = gtk_entry_new ();
+    gtk_entry_set_has_frame(GTK_ENTRY(entry2), FALSE);
+    gtk_entry_set_text (GTK_ENTRY (entry2), "0:00.00");
+    gtk_table_attach_defaults (GTK_TABLE (table), entry2, 1, 3, 1, 2);
+    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry2);
+
+    label = gtk_label_new_with_mnemonic (_("State:"));
+    gtk_table_attach_defaults (GTK_TABLE (table),
+            label,
+            0, 1, 2, 3);
+
+    entry3 = gtk_entry_new ();
+    gtk_entry_set_has_frame(GTK_ENTRY(entry3), FALSE);
+    gtk_entry_set_text (GTK_ENTRY (entry3), RECORDER_MSG_READY);
+    gtk_table_attach_defaults (GTK_TABLE (table), entry3, 1, 3, 2, 3);
+    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry3);
+
+    adjustment = gtk_adjustment_new (0.00,
+                  0.00,
+                  100.00,
+                  0.01,
+                  0.01,
+                  0);
+
+    scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
+      
+/*     gtk_table_attach_defaults (GTK_TABLE (table),
+                label,
+                0, 3, 2, 3);
+*/
+    /* connect signals */
+    g_signal_connect(G_OBJECT(adjustment), "value-changed", G_CALLBACK(cbUserSeek), data);
+    g_signal_connect(G_OBJECT(scale), "format-value", G_CALLBACK(cbFormatSeekbarValue), data);
+    g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(cbDestroy), data);
+
+    /* packing the view */
+    gtk_container_add (GTK_CONTAINER(window), vbox);
+    gtk_box_pack_start (GTK_BOX(vbox), table, FALSE, TRUE, 0);
+    gtk_box_pack_start (GTK_BOX(vbox), scale, FALSE, FALSE, 0);
+//    gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
+    
+    hildon_window_add_toolbar(window, GTK_TOOLBAR(toolBar)); 
+
+    /* initialise the ui */
+    gtk_entry_set_editable(GTK_ENTRY(entry1), FALSE);
+    gtk_entry_set_editable(GTK_ENTRY(entry2), FALSE);
+    gtk_entry_set_editable(GTK_ENTRY(entry3), FALSE);
+
+    /* store needed widgets */
+    data->app = app;
+    data->mainView = window;
+    data->mainViewData.toolBar = GTK_WIDGET(toolBar);
+    data->mainViewData.fileNameEntry = GTK_WIDGET(entry1);
+    data->mainViewData.lengthEntry = GTK_WIDGET(entry2);
+    data->mainViewData.stateEntry = GTK_WIDGET(entry3);
+    data->mainViewData.adjustment = GTK_OBJECT(adjustment);
+
+    /* show the app */
+    gtk_widget_show_all(GTK_WIDGET(window));
+
+    createMenu(data);
+    
+    return TRUE;
+}
+
+void 
+maemo_recorder_mime_open(gpointer user_data, gint argc, gchar **argv)
+{
+    AppData *data;
+
+    ULOG_DEBUG("%s with %d arguments", __FUNCTION__, argc);
+
+    if (argc == 0)
+        return;
+
+    g_assert(user_data);
+    data = (AppData *) user_data;
+
+    if (argv[0] != NULL)
+    {
+        ULOG_DEBUG("request to open %s", argv[0]);
+        g_free(data->mimeURI);
+        data->mimeURI = g_strdup(argv[0]);
+        g_idle_add(openURI, (gpointer) data); 
+        gtk_window_present(GTK_WINDOW(data->mainView));
+    }
+}
+
+static void seekToTime(GstElement *pipeline, gdouble secs)
+{
+    g_assert(NULL != pipeline);
+    ULOG_DEBUG("Seeking to: %.2f", secs);
+
+    /* time must be nanoseconds */
+    if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+            GST_SEEK_TYPE_SET, (gint64) (secs * GST_SECOND),
+            GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+    {
+        ULOG_WARN("seekToTime failed!");
+        return;
+    }
+    ULOG_DEBUG("seekToTime succeeded");
+}
+
+static gboolean seekToZero(AppData *data, GstElement *pipeline)
+{
+    g_assert(NULL != pipeline);
+    ULOG_DEBUG("Seeking to zero");
+
+    /* time must be nanoseconds */
+    if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+            GST_SEEK_TYPE_SET, (gint64) 0,
+            GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+    {
+        ULOG_ERR("seekToZero failed! Trying to destroy and re-create pipeline");
+        gint plType = data->playPipelineType;
+
+        /* gst_element_set_state(pipeline, GST_STATE_READY); */
+        destroyPipeline(data, plType);
+        return createPipeline(data, plType);
+    }
+
+    ULOG_DEBUG("seekToZero succeeded");
+    return TRUE;
+}
+
+static void setLength(AppData *data, gdouble secs)
+{
+    guint mins = 0;
+    gchar *tmp;
+
+    if (secs < 0.0)
+        return;
+
+    if (secs > 0)
+    {
+      g_object_set (G_OBJECT (data->mainViewData.adjustment), 
+            "upper", secs, 
+            NULL);    
+      gtk_adjustment_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
+    }
+
+    if (secs >= 60.0)
+    {
+        mins = secs / 60;
+        secs -= mins * 60.0;
+    }
+
+    tmp = g_strdup_printf("%u:%05.2f", mins, secs);
+
+    /*
+    ULOG_INFO("Setting length to %s", tmp);
+    */
+    gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry), 
+                 tmp);
+    g_free(tmp);
+}
+
+static gdouble guessMediaLength(AppData *data)
+{
+    GnomeVFSFileSize size = 0;
+    gdouble bitrate = 0.0;
+    gdouble len = -1.0;
+
+    if (data->openFileName)
+        size = getFileLength(data->openFileName);
+    else
+        return -1.0;
+           
+    if (size == 0)
+        return -1.0;
+
+    ULOG_DEBUG("file size: %llu bytes", size);
+
+    switch (data->file_format)
+    {
+        case FORMAT_ILBC:
+            bitrate = ILBC_BITRATE_20;
+            break; 
+            
+        case FORMAT_PCMA:
+        case FORMAT_PCMU:
+            bitrate = PCMA_BITRATE;
+            break;
+
+        default:
+            return -1.0;
+    }
+    if (bitrate == 0.0)
+        return -1.0;
+
+    len = (((gdouble) size) * 8.0) / (bitrate);
+    ULOG_DEBUG("guessed media length: %.2f secs", len);
+
+    return len;
+}
+
+static GstCaps *createCapsFilter(AudioFormat format)
+{
+    switch (format)
+    {
+        case FORMAT_ILBC:
+            return gst_caps_new_simple(
+                GST_TYPE_ILBC,
+                "rate", G_TYPE_INT, ILBC_RATE,
+                "channels", G_TYPE_INT, DEFAULT_CHANNELS,
+                "mode", G_TYPE_INT, 20, /* 20 ms frames */
+                NULL);
+        case FORMAT_PCMA:
+            return gst_caps_new_simple(
+                GST_TYPE_PCMA,
+                "rate", G_TYPE_INT, DEFAULT_RATE,
+                "channels", G_TYPE_INT, DEFAULT_CHANNELS,
+                NULL);
+        case FORMAT_PCMU:
+            return gst_caps_new_simple(
+                GST_TYPE_PCMU,
+                "rate", G_TYPE_INT, DEFAULT_RATE,
+                "channels", G_TYPE_INT, DEFAULT_CHANNELS,
+                NULL);
+        case FORMAT_WAV:
+        case FORMAT_PCM:
+            return gst_caps_new_simple(
+                GST_TYPE_PCM,
+                "rate", G_TYPE_INT, PCM_RATE,
+                "signed", G_TYPE_BOOLEAN, TRUE,
+                "channels", G_TYPE_INT, DEFAULT_CHANNELS,
+                "endianness", G_TYPE_INT, PCM_ENDIANNESS,
+                "width", G_TYPE_INT, PCM_WIDTH,
+                "depth", G_TYPE_INT, PCM_DEPTH,
+                NULL);
+        default:
+            ULOG_WARN("%s(): creating ANY caps", G_STRFUNC);
+            return gst_caps_new_any();
+    }
+}
+
+static gboolean cbStopPlayback(AppData *data)
+{
+    gint ret;
+    ULOG_INFO("Stopping playback");
+   
+    g_assert(data != NULL);
+
+    ret = gst_element_set_state(GST_ELEMENT(data->playPipeline), 
+                        GST_STATE_PAUSED);
+    if (seekToZero(data, GST_ELEMENT(data->playPipeline)))
+    {
+      gtk_adjustment_set_value( 
+           GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
+      gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
+    }
+    setAppState(data, APPSTATE_READY);
+    gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
+    gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
+
+    return FALSE;
+}
+
+static void cbUserSeek(GtkAdjustment *adjustment, gpointer data)
+{   
+    /*ULOG_INFO("cbUserSeek");*/
+    AppData *app;
+
+    g_return_if_fail(data != NULL);
+    app = (AppData *) data;
+
+    if (getAppState(app) != APPSTATE_READY || NULL == app->playPipeline)
+        return;
+
+    seekToTime(app->playPipeline, gtk_adjustment_get_value(adjustment));
+}
+
+static gchar *cbFormatSeekbarValue(GtkScale *scale, gdouble value)
+{
+/*    ULOG_INFO("cbFormatSeekbarValue");*/
+    gint mins = 0;
+    gint digits = gtk_scale_get_digits(scale);
+
+    if (value >= 60.0)
+    {
+        mins = value / 60;
+        value -= mins * 60.0;
+        return g_strdup_printf("%d:%0*.*f", mins, digits + 3, digits, value);
+    }
+    /* mins:sec.frac */
+    return g_strdup_printf("%0.*f", digits, value);
+}
+
+static gboolean cbUpdateRecLength(AppData *data)
+{
+    struct timeval tv;
+    guint mins = 0;
+    gdouble secs;
+    gchar *tmp;
+
+    if (gettimeofday(&tv, NULL) != 0)
+        return FALSE;
+
+    secs = tv.tv_sec - data->recStartTv.tv_sec;
+    secs += ((tv.tv_usec - data->recStartTv.tv_usec) / 1000000.0);
+
+    if (secs >= 60.0)
+    {
+        mins = secs / 60;
+        secs -= mins * 60.0;
+        tmp = g_strdup_printf("%u:%05.2f", mins, secs);
+    }
+    else
+        tmp = g_strdup_printf("%0.2f", secs);
+
+    gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry), 
+                 tmp);
+    g_free(tmp);
+
+    if (getAppState(data) == APPSTATE_RECORDING)
+        return TRUE;
+
+    data->recUpdateId = 0;
+    return FALSE;
+}
+