1 /* vim: set sts=4 sw=4 et: */
5 * Copyright (C) 2006 Nokia Corporation
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <glib/gi18n-lib.h>
26 #include <libgnomevfs/gnome-vfs.h>
28 #include <hildon-widgets/hildon-program.h>
29 #include <hildon-widgets/hildon-note.h>
30 #include <hildon-widgets/hildon-banner.h>
31 #include <hildon-widgets/hildon-defines.h>
32 #include <hildon-widgets/hildon-file-system-model.h>
33 #include <hildon-widgets/hildon-file-chooser-dialog.h>
37 #include "maemo-recorder.h"
38 #include "maemo-recorder-ui.h"
39 #include "maemo-recorder-file.h"
42 #define DEFAULT_REC_BLOCKSIZE "160"
44 #define STOP_DELAY 500
45 #define REC_UPDATE_INTERVAL 750
46 #define PLAY_UPDATE_INTERVAL 200
50 #define GST_TIME_MINS(t) \
51 (guint) ((((GstClockTime)(t)) / (GST_SECOND * 60)) % 60)
52 #define GST_TIME_SECS(t) \
53 (guint) ((((GstClockTime)(t)) / GST_SECOND) % 60)
54 #define GST_TIME_TO_SECS(t) \
55 (gdouble) (((gdouble)(t)) / (gdouble) GST_SECOND) /* GST_SECOND should be 1e9 */
56 #define GST_TIME_MSECS(t) \
57 (guint) (((GstClockTime)(t)) % GST_SECOND)
59 #define RECORDER_APP_TITLE "Maemo Recorder"
60 #define RECORDER_MSG_READY _("Ready")
61 #define RECORDER_MSG_STOPPED _("Stopped")
62 #define RECORDER_MSG_PAUSED _("Paused")
63 #define RECORDER_MSG_PLAYING _("Playing")
64 #define RECORDER_MSG_RECORDING _("Recording")
65 #define RECORDER_FILE_UNTITLED _("Untitled")
67 /* general enumerations */
95 /* function prototypes */
97 static gboolean cbBus (GstBus *bus,
101 static void pipelineStateChanged (GstElement *element,
107 static void seekToTime(GstElement *pipeline, gdouble secs);
108 static gboolean seekToZero(AppData *data, GstElement *pipeline);
109 static void setLength(AppData *data, gdouble secs);
110 static gboolean cbStopPlayback(AppData *data);
111 static void cbStop(GtkWidget* widget, AppData *data);
112 static void cbPlay(GtkWidget* widget, AppData *data);
113 static void cbRec(GtkWidget* widget, AppData *data);
114 static void cbNew(GtkWidget* widget, AppData *data);
115 static void cbOpen(GtkWidget* widget, AppData *data);
116 /*static void cbSave(GtkWidget* widget, AppData *data);*/
117 static void cbSaveAs(GtkWidget* widget, AppData *data);
118 static void cbItemClose(GtkWidget *widget, gpointer data);
119 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data);
120 static gchar* cbFormatSeekbarValue(GtkScale *scale, gdouble value);
121 static GtkWidget* createToolBar(AppData *data);
122 static void createMenu( AppData *data );
123 static gboolean createPipeline(AppData *app, PipeLineType type);
124 static void openPlayPipeline( AppData *data );
125 static gboolean destroyPipeline(AppData *data, PipeLineType type);
126 static gboolean destroyPipelines(AppData *data);
127 static void cbItemGroupChanged(gpointer data);
128 static gboolean cbUpdateRecLength(AppData *data);
129 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data);
130 static gboolean openURI(gpointer user_data);
131 static gboolean closeFile(AppData *data);
132 static gdouble guessMediaLength(AppData *data);
133 static GstCaps *createCapsFilter(AudioFormat format);
135 static void new_pad_cb (GstElement *wavparse, GstPad *new_pad, gpointer data)
138 AppData* app = (AppData*) data;
140 ULOG_INFO("new pad");
142 sink = gst_element_factory_make ("dsppcmsink", "sink");
144 gst_bin_add (GST_BIN (app->playPipeline), sink);
146 if (!gst_element_link (wavparse, sink))
147 g_error ("link(wavparse, sink) failed!");
148 gst_element_sync_state_with_parent(sink);
152 static gboolean createPipeline(AppData *app, PipeLineType type)
154 GstElement *src = NULL;
155 GstElement *sink = NULL;
156 GstElement *filter = NULL;
157 GstElement *queue = NULL;
158 GstElement *pipeline = NULL;
159 GstElement *parse = NULL;
160 GstCaps *caps = NULL;
162 g_assert(NULL != app);
164 pipeline = gst_pipeline_new("pipeline");
166 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
169 /* create elements */
172 case PIPELINE_PLAY_MP3:
173 ULOG_INFO("mp3 playback - queue");
174 src = gst_element_factory_make ("gnomevfssrc", "source");
175 queue = gst_element_factory_make ("queue", "queue");
176 sink = gst_element_factory_make ("dspmp3sink", "sink");
178 g_object_set(G_OBJECT (queue),
179 "min-threshold-bytes", 131072,
181 g_object_set(G_OBJECT(src),
182 "location", app->openFileName,
188 src = gst_element_factory_make ("filesrc", "source");
189 /* we need also a filter to modify caps */
190 filter = gst_element_factory_make("capsfilter", "filter");
194 ULOG_INFO("using ilbc sink");
195 sink = gst_element_factory_make ("dspilbcsink", "sink");
201 ULOG_INFO("using pcm sink");
202 sink = gst_element_factory_make ("dsppcmsink", "sink");
206 ULOG_INFO("using wavparse & pcm sink");
207 parse = gst_element_factory_make ("wavparse", "parse");
214 g_object_set(G_OBJECT(src),
215 "location", app->openFileName,
218 caps = createCapsFilter(app->filter);
219 g_object_set(G_OBJECT(filter),
228 ULOG_INFO("using ilbc source");
229 src = gst_element_factory_make("dspilbcsrc", "source");
230 g_object_set(G_OBJECT(src),
238 ULOG_INFO("using pcm source");
239 src = gst_element_factory_make("dsppcmsrc", "source");
240 g_object_set(G_OBJECT (src),
241 "blocksize", DEFAULT_REC_BLOCKSIZE,
247 ULOG_INFO("using pcm source & wavenc");
248 src = gst_element_factory_make("dsppcmsrc", "source");
249 g_object_set(G_OBJECT (src),
250 "blocksize", DEFAULT_REC_BLOCKSIZE,
253 parse = gst_element_factory_make("wavenc", "enc");
257 ULOG_WARN("Unknown filter type!");
261 filter = gst_element_factory_make("capsfilter", "filter");
262 caps = createCapsFilter(app->filter);
263 g_object_set(G_OBJECT(filter),
267 sink = gst_element_factory_make("filesink", "sink");
269 g_object_set(G_OBJECT(sink),
270 "location", app->saveFileName,
275 ULOG_ERR("Invalid pipeline type!");
276 gst_object_unref(pipeline);
280 if (!src || !pipeline)
282 ULOG_ERR("Could not create GstElement!");
286 if (!sink && app->filter != FORMAT_WAV)
288 ULOG_ERR("Could not create GstElement!");
292 ULOG_INFO("Create pipeline");
294 /* add to pipeline and link */
305 ULOG_ERR("Could not create filter GstElement!");
308 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
310 if (!gst_element_link_many (src, filter, sink, NULL))
312 ULOG_ERR("gst_element_link failed for src, filter and sink!");
318 gst_bin_add_many(GST_BIN(pipeline), src, parse, sink, NULL);
319 if (!gst_element_link_many (src, parse, sink, NULL))
321 ULOG_ERR("gst_element_link failed for src, parse and sink!");
339 ULOG_ERR("Could not create filter GstElement!");
342 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
344 if (!gst_element_link_many (src, filter, sink, NULL))
346 ULOG_ERR("gst_element_link failed for src, filter and sink!");
353 gst_bin_add_many(GST_BIN(pipeline), src, parse, NULL);
354 if (!gst_element_link_many (src, parse, NULL))
356 ULOG_ERR("gst_element_link failed for src, parse and sink!");
359 app->playPipeline = pipeline;
360 g_signal_connect(parse, "pad_added",
361 G_CALLBACK(new_pad_cb), app);
370 case PIPELINE_PLAY_MP3:
372 gst_bin_add_many(GST_BIN(pipeline), src, queue, sink, NULL);
374 if(!gst_element_link_many(src, queue, sink, NULL))
376 ULOG_ERR("gst_element_link failed for src and sink!");
383 /* set application data */
384 if (type == PIPELINE_REC)
386 app->recPipeline = pipeline;
390 app->playPipeline = pipeline;
391 app->playPipelineType = type;
396 gst_caps_unref(caps);
403 static gboolean destroyPipelines(AppData *data)
405 gboolean ret = FALSE;
407 /* ugly hack with pipeline types, but works though */
408 ret != destroyPipeline(data, PIPELINE_REC);
409 ret != destroyPipeline(data, PIPELINE_PLAY);
413 static gboolean destroyPipeline(AppData *data, PipeLineType type)
417 GstElement *pipeline = NULL;
419 ULOG_INFO("%s() - Stopping playback/recording", G_STRFUNC);
424 pipeline = data->recPipeline;
426 data->recPipeline = NULL;
431 pipeline = data->playPipeline;
433 data->playPipeline = NULL;
438 if (!GST_IS_ELEMENT(pipeline))
441 /* this unallocates everything */
442 gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
444 /* for some reason the state does not update manually */
445 gst_element_get_state(pipeline, &state,
446 &pending, GST_CLOCK_TIME_NONE);
447 pipelineStateChanged(pipeline,
454 gst_object_unref(pipeline);
463 static void pipelineStateChanged (GstElement *element,
469 g_assert(NULL != data);
473 case GST_STATE_PLAYING:
474 if(APPSTATE_RECORDING == getAppState(data))
476 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_RECORDING);
477 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
480 ULOG_INFO("%s() - Recording", G_STRFUNC);
481 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
482 RECORDER_MSG_RECORDING);
484 gtk_widget_set_state(data->buttonRec, GTK_STATE_ACTIVE);
486 if (data->recUpdateId == 0 && gettimeofday(&data->recStartTv, NULL) == 0)
488 data->recUpdateId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, REC_UPDATE_INTERVAL, (GSourceFunc) cbUpdateRecLength, data, NULL);
493 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_PLAYING);
494 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
497 ULOG_INFO("%s() - Playing", G_STRFUNC);
498 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
499 RECORDER_MSG_PLAYING);
500 gtk_widget_set_state(data->buttonPlay, GTK_STATE_ACTIVE);
502 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PAUSE);
508 case GST_STATE_READY:
509 /* hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, "Ready..."); */
510 ULOG_INFO("%s() - Ready", G_STRFUNC);
511 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
515 case GST_STATE_PAUSED:
518 GstFormat fmt = GST_FORMAT_TIME;
519 ULOG_INFO("%s() - Paused", G_STRFUNC);
521 /* if pipeline pos == 0 => stopped, else => paused */
522 if (GST_IS_ELEMENT(data->playPipeline) && gst_element_query_position(data->playPipeline, &fmt, &pos) && pos != 0)
524 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_PAUSED);
525 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
526 RECORDER_MSG_PAUSED);
528 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
529 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
534 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
535 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
536 RECORDER_MSG_STOPPED);
537 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
538 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
540 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
545 ULOG_INFO("%s() - Null", G_STRFUNC);
546 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
547 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
549 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
550 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
551 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
556 ULOG_WARN("%s() - default case", G_STRFUNC);
562 static gboolean cbBus(GstBus *bus,
566 AppData *app = (AppData*)data;
568 switch (GST_MESSAGE_TYPE(message))
570 case GST_MESSAGE_WARNING:
575 gst_message_parse_error (message, &err, &debug);
576 ULOG_WARN("%s() - Warning: %s", G_STRFUNC, err->message);
582 case GST_MESSAGE_ERROR:
587 gst_message_parse_error (message, &err, &debug);
588 ULOG_ERR("%s() - Error: %s", G_STRFUNC, err->message);
592 /* flow through to eos */
595 case GST_MESSAGE_EOS:
597 ULOG_INFO("%s() - eos", G_STRFUNC);
599 switch(getAppState(app))
601 case APPSTATE_PLAYING:
602 /* stop playback after a short break*/
603 g_timeout_add(STOP_DELAY, (GSourceFunc)cbStopPlayback, data);
606 case APPSTATE_RECORDING:
607 gst_element_set_state(GST_ELEMENT(app->recPipeline),
609 destroyPipeline(app, PIPELINE_REC);
615 /* destroyPipelines(app); */
621 case GST_MESSAGE_STATE_CHANGED:
627 gst_message_parse_state_changed(message, &old, &new, &pending);
629 pipelineStateChanged(NULL, old, new, pending, app);
635 /* unhandled message */
636 ULOG_WARN("%s() - Unhandled message, type = %d", G_STRFUNC, message->type);
640 /* remove message from the queue */
644 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data)
650 app = (AppData *) data;
655 destroyPipelines(app);
656 if (app->playPipeline)
657 gst_object_unref(GST_OBJECT(app->playPipeline));
659 if (app->recPipeline)
660 gst_object_unref(GST_OBJECT(app->recPipeline));
665 static gboolean cbCheckPosition (AppData *data)
667 GstFormat fmt = GST_FORMAT_TIME;
668 gint64 pos = 0, len = 0;
669 static gboolean lengthSet = FALSE;
671 g_assert(NULL != data);
674 if(!lengthSet && gst_element_query_duration(data->playPipeline, &fmt, &len))
679 size = GST_TIME_TO_SECS(len);
680 setLength(data, size); /* sets lengthEntry and adjustment */
685 /* calculate position */
686 if (gst_element_query_position(data->playPipeline, &fmt, &pos))
688 gdouble time = GST_TIME_TO_SECS(pos);
690 ULOG_DEBUG("pos = %lld, time = %f",
695 gtk_adjustment_set_value(
696 GTK_ADJUSTMENT(data->mainViewData.adjustment),
698 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
701 if (APPSTATE_PLAYING == getAppState(data))
709 static void cbNew(GtkWidget* widget, AppData *data)
711 g_assert(NULL != data);
713 if (!closeFile(data))
716 /* remove pipelines if existing */
717 destroyPipelines(data);
718 ULOG_DEBUG_F("cbNew");
719 /* destroy tmp file */
721 /* clear filenames */
722 g_free(data->openFileName);
723 data->openFileName = NULL;
724 g_free(data->saveFileName);
725 data->saveFileName = NULL;
726 /* data->filter = FORMAT_NONE;*/
727 data->file_format = FORMAT_NONE;
730 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
731 RECORDER_FILE_UNTITLED);
732 setLength(data, 0.0);
733 /* update the display + scale */
734 gtk_adjustment_set_value(GTK_ADJUSTMENT(data->mainViewData.adjustment),
736 gtk_widget_set_sensitive(data->buttonSave, FALSE);
737 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
740 gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
742 ULOG_DEBUG_F("cbNew end");
745 static void cbOpen(GtkWidget* widget, AppData *data)
747 GtkWidget* dialog = NULL;
748 gchar *tmpfile = NULL;
749 gchar *selected = NULL;
754 GtkFileFilter *filter;
757 ULOG_DEBUG_F("begin");
758 g_assert(NULL != data);
760 if (!closeFile(data))
765 filter = gtk_file_filter_new();
766 gtk_file_filter_add_mime_type(filter, "audio/x-mp3");
769 g_assert(GTK_IS_WINDOW(data->mainView));
771 dialog = hildon_file_chooser_dialog_new_with_properties(
772 GTK_WINDOW(data->mainView),
773 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
774 "file-system-model", NULL,
780 gtk_widget_show_all(dialog);
782 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
784 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
787 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
789 if (dialog != NULL && GTK_IS_WIDGET(dialog))
791 gtk_widget_destroy(dialog);
793 ULOG_DEBUG("%s() - dialog destroyed", G_STRFUNC);
797 if (NULL == selected) /* no file selected */
800 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
802 if (openFile(selected, &format, &tmpfile))
804 ULOG_INFO("%s() - openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
808 /* update filenames */
809 basename = g_path_get_basename(selected);
811 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
812 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
815 g_free(data->openFileName);
816 data->openFileName = tmpfile;
817 data->file_format = format;
818 data->filter = format;
819 g_free(data->saveFileName);
820 data->saveFileName = NULL;
821 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
823 len = guessMediaLength(data);
825 setLength(data, len);
827 setLength(data, 0.0);
833 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
834 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
843 openURI(gpointer user_data)
847 gchar *selected = NULL;
849 gchar *tmpfile = NULL;
850 gchar *basename = NULL;
854 data = (AppData *) user_data;
856 if (NULL == data->mimeURI)
859 uri = gnome_vfs_uri_new(data->mimeURI);
860 selected = g_strdup(gnome_vfs_uri_get_path(uri));
862 gnome_vfs_uri_unref(uri);
865 g_free(data->mimeURI);
866 data->mimeURI = NULL;
868 /* TODO: the following is duplicated in cbOpen(), move to a tryOpen() function ? */
870 if (NULL == selected)
873 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
875 if (openFile(selected, &format, &tmpfile))
877 ULOG_INFO("%s: openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
881 /* update filenames */
882 basename = g_path_get_basename(selected);
884 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
885 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
888 g_free(data->openFileName);
889 data->openFileName = tmpfile;
890 data->file_format = format;
891 data->filter = format;
892 g_free(data->saveFileName);
893 data->saveFileName = NULL;
894 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
896 len = guessMediaLength(data);
898 setLength(data, len);
900 setLength(data, 0.0);
906 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
907 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
915 static void openPlayPipeline( AppData *data )
918 GstFormat fmt = GST_FORMAT_TIME;
921 /* create pipelines */
922 /* check file type */
923 switch (data->file_format)
930 destroyPipelines(data);
931 data->filter = data->file_format;
932 createPipeline(data, PIPELINE_PLAY);
936 destroyPipelines(data);
937 data->filter = data->file_format;
938 createPipeline(data, PIPELINE_PLAY_MP3);
943 ULOG_WARN("%s() - unknown file_format", G_STRFUNC);
944 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Unknown filetype!"));
949 if (!GST_IS_ELEMENT(data->playPipeline))
951 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline!"));
955 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_READY);
956 gst_element_get_state(GST_ELEMENT(data->playPipeline), NULL, NULL, GST_CLOCK_TIME_NONE /* or ns */);
958 /* calculate length */
959 if (gst_element_query_duration (data->playPipeline, &fmt, &len))
963 size = GST_TIME_TO_SECS(len);
964 ULOG_INFO("playSize: len:%lld size:%f", len, size);
965 setLength(data, size);
971 ULOG_INFO("playSize else");
972 setLength(data, 0.0);
977 /* returns whether the action can proceed or should be aborted */
979 closeFile(AppData *data)
987 note = hildon_note_new_confirmation_add_buttons(GTK_WINDOW(data->mainView), _("Save recording?"),
988 _("Yes"), GTK_RESPONSE_YES,
989 _("No"), GTK_RESPONSE_NO,
990 _("Cancel"), GTK_RESPONSE_CANCEL,
993 i = gtk_dialog_run(GTK_DIALOG(note));
994 gtk_widget_destroy(note);
998 case GTK_RESPONSE_CANCEL:
1001 case GTK_RESPONSE_NO:
1004 case GTK_RESPONSE_YES:
1006 cbSaveAs(NULL, data);
1010 ULOG_WARN("%s(): unknown response from dialog: %d", G_STRFUNC, i);
1016 static void cbSave(GtkWidget* widget, AppData *data)
1018 GtkWidget* dialog = NULL;
1019 const gchar *current;
1020 gchar *selected = NULL;
1024 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1026 current = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1027 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1029 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1033 /* if saveFileName does not exist run saveas */
1034 if (NULL == data->saveFileName)
1037 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1038 GTK_WINDOW(data->mainView),
1039 GTK_FILE_CHOOSER_ACTION_SAVE));
1042 gtk_widget_show_all(dialog);
1044 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1046 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1049 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1051 gtk_widget_destroy(dialog);
1053 if (NULL != selected)
1055 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC,
1057 g_free(data->saveFileName);
1058 data->saveFileName = g_strdup_printf("%s%s", selected, getExtension(data->file_format));
1069 if (doSave(gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry)), data->saveFileName, data->file_format))
1071 gchar *basename = g_path_get_basename(data->saveFileName);
1072 ULOG_INFO("%s() - file succesfully saved!", G_STRFUNC);
1073 g_free(data->openFileName);
1074 data->openFileName = g_strdup(data->saveFileName);
1076 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1077 data->saveFileName);
1078 gtk_widget_set_sensitive(data->buttonSave, FALSE);
1079 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
1083 ULOG_DEBUG("%s() - end", G_STRFUNC);
1087 static void cbSettings(GtkWidget* widget, AppData *data)
1089 settings_edit( widget, data );
1092 static void cbSaveAs(GtkWidget* widget, AppData *data)
1094 GtkWidget* dialog = NULL;
1095 const gchar *current;
1096 gchar *selected = NULL;
1098 g_assert(NULL != data);
1100 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1102 current = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1103 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1105 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1110 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1111 GTK_WINDOW(data->mainView),
1112 GTK_FILE_CHOOSER_ACTION_SAVE));
1114 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog),
1115 get_default_dir() );
1118 gtk_widget_show_all(dialog);
1120 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1122 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1125 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1126 gtk_widget_destroy(dialog);
1128 if (NULL == selected)
1131 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
1133 g_free(data->saveFileName);
1134 data->saveFileName = NULL;
1136 if (saveFile(selected, data->openFileName, data->file_format, &(data->saveFileName)))
1141 g_assert(data->saveFileName);
1143 /* set new title that has the file name */
1144 basename = g_path_get_basename(data->saveFileName);
1145 ULOG_DEBUG("%s() - file '%s' succesfully saved!", G_STRFUNC, data->saveFileName);
1147 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
1149 /* Houston, we have a kludge:
1150 * for AU files we need to keep the old tmpfile for playback
1151 * for RAW/iLBC files, we can remove the tmpfile and point openFileName to the saved file
1153 ext = getExtension(data->file_format);
1154 if (strcmp(ext, EXTENSION_AU) != 0)
1156 g_free(data->openFileName);
1157 data->openFileName = g_strdup(data->saveFileName);
1160 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1161 data->saveFileName);
1168 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Saving file failed!"));
1174 ULOG_DEBUG("%s() - end", G_STRFUNC);
1177 static void cbRec(GtkWidget* widget, AppData *data)
1179 g_assert(NULL != data);
1181 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1183 if (APPSTATE_READY != getAppState(data))
1185 ULOG_WARN("%s() - state different than READY -> return", G_STRFUNC);
1189 if (!closeFile(data))
1192 /* clear filenames, use tmp file */
1193 g_free(data->openFileName);
1194 data->openFileName = NULL;
1196 g_free(data->saveFileName);
1197 data->saveFileName = NULL;
1199 switch (data->filter)
1202 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1203 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1207 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1208 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1212 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1213 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1217 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1218 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1223 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1224 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1228 ULOG_INFO("%s() - creating pipelines", G_STRFUNC);
1229 /* start recording */
1230 /* create related pipelines */
1231 if (createPipeline(data, PIPELINE_REC))
1233 ULOG_INFO("%s() - starting recording", G_STRFUNC);
1234 /* start recording */
1235 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1238 /* update display */
1239 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1240 data->saveFileName);
1242 setAppState(data, APPSTATE_RECORDING);
1243 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1244 gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
1245 data->file_format = data->filter;
1249 ULOG_ERR("Could not create rec pipeline!");
1250 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline"));
1251 setAppState(data, APPSTATE_READY);
1254 ULOG_DEBUG("%s() - end", G_STRFUNC);
1257 static void cbPlay(GtkWidget* widget, AppData *data)
1259 const gchar * file = NULL;
1261 g_assert(NULL != data);
1263 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1265 file = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1266 if (NULL == data->openFileName || NULL == file || strcmp(file, RECORDER_FILE_UNTITLED) == 0)
1268 ULOG_WARN("%s() - nothing to play", G_STRFUNC);
1272 openPlayPipeline(data);
1274 if (APPSTATE_PLAYING == getAppState(data))
1276 if (GST_IS_ELEMENT(data->playPipeline))
1278 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_PAUSED);
1279 setAppState(data, APPSTATE_READY);
1284 if (APPSTATE_READY != getAppState(data))
1286 ULOG_WARN("%s() - state different than PLAYING or READY -> return", G_STRFUNC);
1290 ULOG_INFO("filename %s", file);
1292 /*openPlayPipeline( data );*/
1294 /*if ( ! GST_IS_ELEMENT(data->playPipeline) )
1296 if (g_strrstr(data->openFileName, EXTENSION_RAW))
1298 ULOG_INFO("cbOpen() - file was raw, assuming audio/x-raw-int, 8kHz, 1 ch, 16-bit");
1299 destroyPipelines(data);
1300 createPipeline(data, PIPELINE_PLAY);
1304 if (! GST_IS_ELEMENT(data->playPipeline))
1306 ULOG_WARN("%s() - playPipeline does not exist", G_STRFUNC);
1310 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1313 setAppState(data, APPSTATE_PLAYING);
1315 g_timeout_add(PLAY_UPDATE_INTERVAL, (GSourceFunc)cbCheckPosition, data);
1317 ULOG_DEBUG("%s() - end", G_STRFUNC);
1320 static void cbStop(GtkWidget* widget, AppData *data)
1322 g_assert(NULL != data);
1324 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1326 /* check if we are playing/recording */
1329 if (APPSTATE_PLAYING != getAppState(data) &&
1330 APPSTATE_RECORDING != getAppState(data))
1332 ULOG_WARN("cbStop() - state different than PLAYING or RECORDING "
1338 /* stop playing or recording */
1339 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
1340 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1341 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
1343 /* destroy related pipeline */
1344 switch(getAppState(data))
1346 case APPSTATE_PLAYING:
1347 /* don't destroy the playing pipeline. Instead, set the pipeline to PAUSED */
1348 /* destroyPipeline(data, PIPELINE_PLAY); */
1349 ULOG_INFO("%s() - Setting playPipeline state to PAUSED", G_STRFUNC);
1350 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1353 case APPSTATE_READY:
1354 /* seek to zero, but not for PCM pipeline */
1355 /* if (data->playPipelineType == PIPELINE_PLAY || seekToZero(data, GST_ELEMENT(data->playPipeline))) */
1356 if ( !GST_IS_ELEMENT(data->playPipeline) || seekToZero(data, GST_ELEMENT(data->playPipeline)))
1358 gtk_adjustment_set_value(
1359 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1360 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1361 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
1362 RECORDER_MSG_STOPPED);
1366 case APPSTATE_RECORDING:
1369 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1371 destroyPipeline(data, PIPELINE_REC);
1372 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1373 data->saved = FALSE;
1375 len = guessMediaLength(data);
1377 setLength(data, len);
1383 /* seekToZero(data, GST_ELEMENT(data->playPipeline)); */
1384 /* should not come here */
1388 setAppState(data, APPSTATE_READY);
1390 ULOG_DEBUG("%s() - end", G_STRFUNC);
1394 /* ui construction functions */
1396 static GtkWidget* createToolBar(AppData *data)
1398 GtkToolbar* toolBar = NULL;
1400 GtkToolItem* new = NULL;
1401 GtkToolItem* open = NULL;
1402 GtkToolItem* save = NULL;
1403 GtkToolItem* saveas = NULL;
1404 GtkToolItem* sep = NULL;
1405 GtkToolItem* play = NULL;
1406 GtkToolItem* rec = NULL;
1407 GtkToolItem* stop = NULL;
1409 /* create buttons */
1410 new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
1411 open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
1412 save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
1413 data->buttonSave = GTK_WIDGET(save);
1414 saveas = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE_AS);
1415 data->buttonSaveAs = GTK_WIDGET(saveas);
1416 gtk_widget_set_sensitive(data->buttonSave, FALSE);
1417 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
1420 rec = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_RECORD);
1421 data->buttonRec = GTK_WIDGET(rec);
1422 play = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
1423 data->buttonPlay = GTK_WIDGET(play);
1424 stop = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
1426 /* create separator */
1427 sep = gtk_separator_tool_item_new();
1429 /* create the toolbar itself */
1430 toolBar = GTK_TOOLBAR(gtk_toolbar_new());
1432 /* add items to toolbar */
1433 gtk_toolbar_insert(toolBar, new, -1);
1434 gtk_toolbar_insert(toolBar, open, -1);
1436 gtk_toolbar_insert(toolBar, save, -1);
1438 gtk_toolbar_insert(toolBar, saveas, -1);
1439 gtk_toolbar_insert(toolBar, sep, -1);
1440 gtk_toolbar_insert(toolBar, rec, -1);
1441 gtk_toolbar_insert(toolBar, play, -1);
1442 gtk_toolbar_insert(toolBar, stop, -1);
1444 /* connect signals */
1445 g_signal_connect(G_OBJECT(new), "clicked",
1448 g_signal_connect(G_OBJECT(open), "clicked",
1452 g_signal_connect(G_OBJECT(save), "clicked",
1456 g_signal_connect(G_OBJECT(saveas), "clicked",
1457 G_CALLBACK(cbSaveAs),
1459 g_signal_connect(G_OBJECT(rec), "clicked",
1462 g_signal_connect(G_OBJECT(play), "clicked",
1465 g_signal_connect(G_OBJECT(stop), "clicked",
1469 return GTK_WIDGET(toolBar);
1473 static void cbItemGroupChanged( gpointer data )
1475 AppData* app = (AppData* ) data;
1476 GValue active ={G_TYPE_INVALID};
1479 g_value_init(&active, G_TYPE_INT);
1481 g_object_get_property(G_OBJECT(app->radio_pcma), "active", &active);
1482 pcma = g_value_get_int(&active);
1483 g_object_get_property(G_OBJECT(app->radio_ilbc), "active", &active);
1484 ilbc = g_value_get_int(&active);
1485 g_object_get_property(G_OBJECT(app->radio_pcm), "active", &active);
1486 pcm = g_value_get_int(&active);
1488 ULOG_INFO("change type pcma=%d ilbc=%d pcm=%d",pcma, ilbc, pcm);
1490 app->filter = FORMAT_PCMA;
1491 else if ( ilbc == 1 )
1492 app->filter = FORMAT_ILBC;
1493 else if ( pcm == 1 )
1494 app->filter = FORMAT_WAV;
1498 ULOG_INFO("filter type=%d", app->filter);
1501 static void cbItemClose(GtkWidget *widget, gpointer data)
1505 if (!closeFile(data))
1511 /* Create the menu items needed for the main view */
1512 static void createMenu( AppData *data )
1514 /* Create needed variables */
1515 GSList *group = NULL;
1517 GtkWidget *menu_file;
1518 GtkWidget *menu_others;
1519 GtkWidget *item_file;
1520 GtkWidget *item_file_open;
1521 GtkWidget *item_file_save_as;
1522 GtkWidget *item_others;
1523 GtkWidget *item_pcma;
1524 GtkWidget *item_pcmu;
1525 GtkWidget *item_ilbc;
1526 GtkWidget *item_pcm;
1527 GtkWidget *item_settings;
1529 GtkWidget *item_radio_type1;
1531 GtkWidget *item_close;
1532 GtkWidget *item_separator;
1534 /* Get the menu from view */
1535 main_menu = GTK_MENU(gtk_menu_new());
1536 hildon_window_set_menu(data->mainView, main_menu);
1538 /* Create new submenu for "Others" */
1539 menu_file = gtk_menu_new ();
1540 menu_others = gtk_menu_new ();
1542 /* Create menu items */
1543 item_file = gtk_menu_item_new_with_label (_("File"));
1544 item_file_open = gtk_menu_item_new_with_label(_("Open..."));
1545 item_file_save_as = gtk_menu_item_new_with_label(_("Save as..."));
1546 item_others = gtk_menu_item_new_with_label (_("Recording format"));
1547 item_settings = gtk_menu_item_new_with_label (_("Settings"));
1549 item_pcma = gtk_radio_menu_item_new_with_label(
1550 group, FORMAT_NAME_PCMA);
1551 item_ilbc = gtk_radio_menu_item_new_with_label_from_widget(
1552 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_ILBC);
1553 item_pcmu = gtk_radio_menu_item_new_with_label_from_widget(
1554 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_PCMU);
1555 item_pcm = gtk_radio_menu_item_new_with_label_from_widget(
1556 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_WAV);
1558 data->filter = get_default_filter();
1560 if (data->filter == FORMAT_ILBC)
1561 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_ilbc), TRUE);
1562 else if (data->filter == FORMAT_WAV)
1563 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_pcm), TRUE);
1564 else if (data->filter == FORMAT_PCMA)
1565 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_pcma), TRUE);
1568 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_ilbc), TRUE);
1569 data->filter = FORMAT_ILBC;
1572 data->radio_pcma = item_pcma;
1573 data->radio_ilbc = item_ilbc;
1574 data->radio_pcm = item_pcm;
1576 data->radiotype = item_radio_type1;
1578 item_close = gtk_menu_item_new_with_label(_("Close"));
1579 item_separator = gtk_separator_menu_item_new();
1581 /* Add menu items to right menus */
1582 gtk_menu_append( main_menu, item_file );
1583 gtk_menu_append( menu_file, item_file_open );
1584 gtk_menu_append( menu_file, item_file_save_as );
1585 gtk_menu_append( main_menu, item_others );
1586 gtk_menu_append( menu_others, item_pcm );
1587 gtk_menu_append( menu_others, item_pcma );
1588 gtk_menu_append( menu_others, item_ilbc);
1590 gtk_menu_append( main_menu, item_settings );
1592 gtk_menu_append( main_menu, item_close );
1594 /* Add others submenu to the "Others" item */
1595 gtk_menu_item_set_submenu(
1596 GTK_MENU_ITEM(item_file), menu_file );
1597 gtk_menu_item_set_submenu(
1598 GTK_MENU_ITEM(item_others), menu_others );
1600 /* Attach the callback functions to the activate signal */
1601 g_signal_connect( G_OBJECT( item_file_open), "activate",
1602 GTK_SIGNAL_FUNC (cbOpen), data);
1603 g_signal_connect( G_OBJECT( item_file_save_as), "activate",
1604 GTK_SIGNAL_FUNC (cbSaveAs), data);
1605 g_signal_connect( G_OBJECT( item_settings ), "activate",
1606 GTK_SIGNAL_FUNC (cbSettings), data);
1608 g_signal_connect( G_OBJECT( item_close ), "activate",
1609 GTK_SIGNAL_FUNC (cbItemClose), data);
1611 g_signal_connect_swapped(G_OBJECT(item_pcma), "activate", G_CALLBACK(cbItemGroupChanged), data);
1612 g_signal_connect_swapped(G_OBJECT(item_pcm), "activate", G_CALLBACK(cbItemGroupChanged), data);
1614 /* Make all menu widgets visible */
1616 gtk_widget_show_all( GTK_WIDGET( main_menu ) );
1619 gboolean maemo_recorder_ui_new(AppData *data)
1621 HildonProgram *app = NULL;
1622 HildonWindow *window = NULL;
1623 GtkWidget *hbox = NULL;
1624 GtkWidget *vbox = NULL;
1625 GtkWidget *label = NULL;
1626 GtkWidget *entry1 = NULL;
1627 GtkWidget *entry2 = NULL;
1628 GtkWidget *entry3 = NULL;
1629 GtkWidget *toolBar = NULL;
1630 GtkWidget *table = NULL;
1631 GtkWidget *scale = NULL;
1632 GtkObject *adjustment = NULL;
1634 g_assert(NULL != data);
1636 app = HILDON_PROGRAM(hildon_program_get_instance());
1637 g_set_application_name(RECORDER_APP_TITLE);
1640 window = HILDON_WINDOW(hildon_window_new());
1642 hildon_program_add_window(app, window);
1644 /* content for main view */
1646 /* create vbox, divides control area and view area */
1647 vbox = gtk_vbox_new(FALSE, 0);
1649 /* create hbox to divide control area */
1650 hbox = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
1652 /* create toolbar */
1653 toolBar = createToolBar(data);
1655 /* create table for labels */
1656 table = gtk_table_new (4, 3, FALSE);
1657 gtk_table_set_homogeneous(GTK_TABLE(table), FALSE);
1659 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
1660 gtk_table_set_col_spacings (GTK_TABLE (table), 0);
1662 label = gtk_label_new_with_mnemonic(_("Filename:"));
1664 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1666 gtk_table_attach_defaults (GTK_TABLE (table),
1670 entry1 = gtk_entry_new ();
1671 gtk_entry_set_has_frame(GTK_ENTRY(entry1), FALSE);
1672 gtk_entry_set_text (GTK_ENTRY (entry1), _(RECORDER_FILE_UNTITLED));
1673 gtk_table_attach_defaults (GTK_TABLE (table), entry1, 1, 3, 0, 1);
1674 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry1);
1676 label = gtk_label_new_with_mnemonic (_("Length:"));
1678 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1680 gtk_table_attach_defaults (GTK_TABLE (table),
1684 entry2 = gtk_entry_new ();
1685 gtk_entry_set_has_frame(GTK_ENTRY(entry2), FALSE);
1686 gtk_entry_set_text (GTK_ENTRY (entry2), "0:00.00");
1687 gtk_table_attach_defaults (GTK_TABLE (table), entry2, 1, 3, 1, 2);
1688 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry2);
1690 label = gtk_label_new_with_mnemonic (_("State:"));
1692 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1694 gtk_table_attach_defaults (GTK_TABLE (table),
1698 entry3 = gtk_entry_new ();
1699 gtk_entry_set_has_frame(GTK_ENTRY(entry3), FALSE);
1700 gtk_entry_set_text (GTK_ENTRY (entry3), RECORDER_MSG_READY);
1701 gtk_table_attach_defaults (GTK_TABLE (table), entry3, 1, 3, 2, 3);
1702 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry3);
1704 adjustment = gtk_adjustment_new (0.00,
1711 scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1713 /* gtk_table_attach_defaults (GTK_TABLE (table),
1717 /* connect signals */
1718 g_signal_connect(G_OBJECT(adjustment), "value-changed", G_CALLBACK(cbUserSeek), data);
1719 g_signal_connect(G_OBJECT(scale), "format-value", G_CALLBACK(cbFormatSeekbarValue), data);
1720 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(cbDestroy), data);
1722 /* packing the view */
1723 gtk_container_add (GTK_CONTAINER(window), vbox);
1724 gtk_box_pack_start (GTK_BOX(vbox), table, FALSE, TRUE, 0);
1725 gtk_box_pack_start (GTK_BOX(vbox), scale, FALSE, FALSE, 0);
1726 /* gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 0); */
1728 hildon_window_add_toolbar(window, GTK_TOOLBAR(toolBar));
1730 /* initialise the ui */
1731 gtk_entry_set_editable(GTK_ENTRY(entry1), FALSE);
1732 gtk_entry_set_editable(GTK_ENTRY(entry2), FALSE);
1733 gtk_entry_set_editable(GTK_ENTRY(entry3), FALSE);
1735 /* store needed widgets */
1737 data->mainView = window;
1738 data->mainViewData.toolBar = GTK_WIDGET(toolBar);
1739 data->mainViewData.fileNameEntry = GTK_WIDGET(entry1);
1740 data->mainViewData.lengthEntry = GTK_WIDGET(entry2);
1741 data->mainViewData.stateEntry = GTK_WIDGET(entry3);
1742 data->mainViewData.adjustment = GTK_OBJECT(adjustment);
1745 gtk_widget_show_all(GTK_WIDGET(window));
1753 maemo_recorder_mime_open(gpointer user_data, gint argc, gchar **argv)
1757 ULOG_DEBUG("%s with %d arguments", __FUNCTION__, argc);
1762 g_assert(user_data);
1763 data = (AppData *) user_data;
1765 if (argv[0] != NULL)
1767 ULOG_DEBUG("request to open %s", argv[0]);
1768 g_free(data->mimeURI);
1769 data->mimeURI = g_strdup(argv[0]);
1770 g_idle_add(openURI, (gpointer) data);
1771 gtk_window_present(GTK_WINDOW(data->mainView));
1775 static void seekToTime(GstElement *pipeline, gdouble secs)
1777 g_assert(NULL != pipeline);
1778 ULOG_DEBUG("Seeking to: %.2f", secs);
1780 /* time must be nanoseconds */
1781 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1782 GST_SEEK_TYPE_SET, (gint64) (secs * GST_SECOND),
1783 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1785 ULOG_WARN("seekToTime failed!");
1788 ULOG_DEBUG("seekToTime succeeded");
1791 static gboolean seekToZero(AppData *data, GstElement *pipeline)
1794 g_assert(NULL != pipeline);
1795 ULOG_DEBUG("Seeking to zero");
1797 /* time must be nanoseconds */
1798 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1799 GST_SEEK_TYPE_SET, (gint64) 0,
1800 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1802 ULOG_ERR("seekToZero failed! Trying to destroy and re-create pipeline");
1803 plType = data->playPipelineType;
1805 /* gst_element_set_state(pipeline, GST_STATE_READY); */
1806 destroyPipeline(data, plType);
1807 return createPipeline(data, plType);
1810 ULOG_DEBUG("seekToZero succeeded");
1814 static void setLength(AppData *data, gdouble secs)
1824 g_object_set(G_OBJECT(data->mainViewData.adjustment),
1827 gtk_adjustment_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1833 secs -= mins * 60.0;
1836 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
1839 ULOG_INFO("Setting length to %s", tmp);
1841 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
1846 static gdouble guessMediaLength(AppData *data)
1848 GnomeVFSFileSize size = 0;
1849 gdouble bitrate = 0.0;
1852 if (data->openFileName)
1853 size = getFileLength(data->openFileName);
1860 ULOG_DEBUG("file size: %llu bytes", size);
1862 switch (data->file_format)
1865 bitrate = ILBC_BITRATE_20;
1870 bitrate = PCMA_BITRATE;
1880 len = (((gdouble) size) * 8.0) / (bitrate);
1881 ULOG_DEBUG("guessed media length: %.2f secs", len);
1886 static GstCaps *createCapsFilter(AudioFormat format)
1891 return gst_caps_new_simple(
1893 "rate", G_TYPE_INT, ILBC_RATE,
1894 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1895 "mode", G_TYPE_INT, 20, /* 20 ms frames */
1898 return gst_caps_new_simple(
1900 "rate", G_TYPE_INT, DEFAULT_RATE,
1901 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1904 return gst_caps_new_simple(
1906 "rate", G_TYPE_INT, DEFAULT_RATE,
1907 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1911 return gst_caps_new_simple(
1913 "rate", G_TYPE_INT, PCM_RATE,
1914 "signed", G_TYPE_BOOLEAN, TRUE,
1915 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1916 "endianness", G_TYPE_INT, PCM_ENDIANNESS,
1917 "width", G_TYPE_INT, PCM_WIDTH,
1918 "depth", G_TYPE_INT, PCM_DEPTH,
1921 ULOG_WARN("%s(): creating ANY caps", G_STRFUNC);
1922 return gst_caps_new_any();
1926 static gboolean cbStopPlayback(AppData *data)
1929 ULOG_INFO("Stopping playback");
1931 g_assert(data != NULL);
1933 ret = gst_element_set_state(GST_ELEMENT(data->playPipeline),
1935 if (seekToZero(data, GST_ELEMENT(data->playPipeline)))
1937 gtk_adjustment_set_value(
1938 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1939 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1941 setAppState(data, APPSTATE_READY);
1942 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
1943 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1948 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data)
1950 /*ULOG_INFO("cbUserSeek");*/
1953 g_return_if_fail(data != NULL);
1954 app = (AppData *) data;
1956 if (getAppState(app) != APPSTATE_READY || NULL == app->playPipeline)
1959 seekToTime(app->playPipeline, gtk_adjustment_get_value(adjustment));
1962 static gchar *cbFormatSeekbarValue(GtkScale *scale, gdouble value)
1964 /* ULOG_INFO("cbFormatSeekbarValue");*/
1966 gint digits = gtk_scale_get_digits(scale);
1971 value -= mins * 60.0;
1972 return g_strdup_printf("%d:%0*.*f", mins, digits + 3, digits, value);
1975 return g_strdup_printf("%0.*f", digits, value);
1978 static gboolean cbUpdateRecLength(AppData *data)
1985 if (gettimeofday(&tv, NULL) != 0)
1988 secs = tv.tv_sec - data->recStartTv.tv_sec;
1989 secs += ((tv.tv_usec - data->recStartTv.tv_usec) / 1000000.0);
1994 secs -= mins * 60.0;
1995 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
1998 tmp = g_strdup_printf("%0.2f", secs);
2000 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
2004 if (getAppState(data) == APPSTATE_RECORDING)
2007 data->recUpdateId = 0;