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>
36 #include "osso-helplib.h"
37 #include <ossoemailinterface.h>
39 #include "maemo-recorder.h"
40 #include "maemo-recorder-ui.h"
41 #include "maemo-recorder-file.h"
44 #define DEFAULT_REC_BLOCKSIZE "160"
46 #define STOP_DELAY 500
47 #define REC_UPDATE_INTERVAL 750
48 #define PLAY_UPDATE_INTERVAL 200
52 #define GST_TIME_MINS(t) \
53 (guint) ((((GstClockTime)(t)) / (GST_SECOND * 60)) % 60)
54 #define GST_TIME_SECS(t) \
55 (guint) ((((GstClockTime)(t)) / GST_SECOND) % 60)
56 #define GST_TIME_TO_SECS(t) \
57 (gdouble) (((gdouble)(t)) / (gdouble) GST_SECOND) /* GST_SECOND should be 1e9 */
58 #define GST_TIME_MSECS(t) \
59 (guint) (((GstClockTime)(t)) % GST_SECOND)
61 #define RECORDER_APP_TITLE "Maemo Recorder"
62 #define RECORDER_MSG_READY _("Ready")
63 #define RECORDER_MSG_STOPPED _("Stopped")
64 #define RECORDER_MSG_PAUSED _("Paused")
65 #define RECORDER_MSG_PLAYING _("Playing")
66 #define RECORDER_MSG_RECORDING _("Recording")
67 #define RECORDER_FILE_UNTITLED _("Untitled")
69 /* general enumerations */
97 /* function prototypes */
99 static gboolean cbBus (GstBus *bus,
103 static void pipelineStateChanged (GstElement *element,
109 static void seekToTime(GstElement *pipeline, gdouble secs);
110 static gboolean seekToZero(AppData *data, GstElement *pipeline);
111 static void setLength(AppData *data, gdouble secs);
112 static gboolean cbStopPlayback(AppData *data);
113 static void cbStop(GtkWidget* widget, AppData *data);
114 static void cbPlay(GtkWidget* widget, AppData *data);
115 static void cbRec(GtkWidget* widget, AppData *data);
116 static void cbNew(GtkWidget* widget, AppData *data);
117 static void cbOpen(GtkWidget* widget, AppData *data);
118 /*static void cbSave(GtkWidget* widget, AppData *data);*/
119 static void cbSaveAs(GtkWidget* widget, AppData *data);
120 static void cbItemClose(GtkWidget *widget, gpointer data);
121 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data);
122 static gchar* cbFormatSeekbarValue(GtkScale *scale, gdouble value);
123 static GtkWidget* createToolBar(AppData *data);
124 static void createMenu( AppData *data );
125 static gboolean createPipeline(AppData *app, PipeLineType type);
126 static void openPlayPipeline( AppData *data );
127 static gboolean destroyPipeline(AppData *data, PipeLineType type);
128 static gboolean destroyPipelines(AppData *data);
129 static void cbItemGroupChanged(gpointer data);
130 static gboolean cbUpdateRecLength(AppData *data);
131 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data);
132 static gboolean openURI(gpointer user_data);
133 static gboolean closeFile(AppData *data);
134 static gdouble guessMediaLength(AppData *data);
135 static GstCaps *createCapsFilter(AudioFormat format);
137 static void new_pad_cb (GstElement *wavparse, GstPad *new_pad, gpointer data)
140 AppData* app = (AppData*) data;
142 ULOG_INFO("new pad");
144 sink = gst_element_factory_make ("dsppcmsink", "sink");
146 gst_bin_add (GST_BIN (app->playPipeline), sink);
148 if (!gst_element_link (wavparse, sink))
149 g_error ("link(wavparse, sink) failed!");
150 gst_element_sync_state_with_parent(sink);
154 static gboolean createPipeline(AppData *app, PipeLineType type)
156 GstElement *src = NULL;
157 GstElement *sink = NULL;
158 GstElement *filter = NULL;
159 GstElement *queue = NULL;
160 GstElement *pipeline = NULL;
161 GstElement *parse = NULL;
162 GstCaps *caps = NULL;
164 g_assert(NULL != app);
166 pipeline = gst_pipeline_new("pipeline");
168 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
171 /* create elements */
174 case PIPELINE_PLAY_MP3:
175 ULOG_INFO("mp3 playback - queue");
176 src = gst_element_factory_make ("gnomevfssrc", "source");
177 queue = gst_element_factory_make ("queue", "queue");
178 sink = gst_element_factory_make ("dspmp3sink", "sink");
180 g_object_set(G_OBJECT (queue),
181 "min-threshold-bytes", 131072,
183 g_object_set(G_OBJECT(src),
184 "location", app->openFileName,
190 src = gst_element_factory_make ("filesrc", "source");
191 /* we need also a filter to modify caps */
192 filter = gst_element_factory_make("capsfilter", "filter");
196 ULOG_INFO("using ilbc sink");
197 sink = gst_element_factory_make ("dspilbcsink", "sink");
203 ULOG_INFO("using pcm sink");
204 sink = gst_element_factory_make ("dsppcmsink", "sink");
208 ULOG_INFO("using wavparse & pcm sink");
209 parse = gst_element_factory_make ("wavparse", "parse");
216 g_object_set(G_OBJECT(src),
217 "location", app->openFileName,
220 caps = createCapsFilter(app->filter);
221 g_object_set(G_OBJECT(filter),
230 ULOG_INFO("using ilbc source");
231 src = gst_element_factory_make("dspilbcsrc", "source");
232 g_object_set(G_OBJECT(src),
240 ULOG_INFO("using pcm source");
241 src = gst_element_factory_make("dsppcmsrc", "source");
242 g_object_set(G_OBJECT (src),
243 "blocksize", DEFAULT_REC_BLOCKSIZE,
249 ULOG_INFO("using pcm source & wavenc");
250 src = gst_element_factory_make("dsppcmsrc", "source");
251 g_object_set(G_OBJECT (src),
252 "blocksize", DEFAULT_REC_BLOCKSIZE,
255 parse = gst_element_factory_make("wavenc", "enc");
259 ULOG_WARN("Unknown filter type!");
263 filter = gst_element_factory_make("capsfilter", "filter");
264 caps = createCapsFilter(app->filter);
265 g_object_set(G_OBJECT(filter),
269 sink = gst_element_factory_make("filesink", "sink");
271 g_object_set(G_OBJECT(sink),
272 "location", app->saveFileName,
277 ULOG_ERR("Invalid pipeline type!");
278 gst_object_unref(pipeline);
282 if (!src || !pipeline)
284 ULOG_ERR("Could not create GstElement!");
288 if (!sink && app->filter != FORMAT_WAV)
290 ULOG_ERR("Could not create GstElement!");
294 ULOG_INFO("Create pipeline");
296 /* add to pipeline and link */
307 ULOG_ERR("Could not create filter GstElement!");
310 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
312 if (!gst_element_link_many (src, filter, sink, NULL))
314 ULOG_ERR("gst_element_link failed for src, filter and sink!");
320 gst_bin_add_many(GST_BIN(pipeline), src, parse, sink, NULL);
321 if (!gst_element_link_many (src, parse, sink, NULL))
323 ULOG_ERR("gst_element_link failed for src, parse and sink!");
341 ULOG_ERR("Could not create filter GstElement!");
344 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
346 if (!gst_element_link_many (src, filter, sink, NULL))
348 ULOG_ERR("gst_element_link failed for src, filter and sink!");
355 gst_bin_add_many(GST_BIN(pipeline), src, parse, NULL);
356 if (!gst_element_link_many (src, parse, NULL))
358 ULOG_ERR("gst_element_link failed for src, parse and sink!");
361 app->playPipeline = pipeline;
362 g_signal_connect(parse, "pad_added",
363 G_CALLBACK(new_pad_cb), app);
372 case PIPELINE_PLAY_MP3:
374 gst_bin_add_many(GST_BIN(pipeline), src, queue, sink, NULL);
376 if(!gst_element_link_many(src, queue, sink, NULL))
378 ULOG_ERR("gst_element_link failed for src and sink!");
385 /* set application data */
386 if (type == PIPELINE_REC)
388 app->recPipeline = pipeline;
392 app->playPipeline = pipeline;
393 app->playPipelineType = type;
398 gst_caps_unref(caps);
405 static gboolean destroyPipelines(AppData *data)
407 gboolean ret = FALSE;
409 /* ugly hack with pipeline types, but works though */
410 ret != destroyPipeline(data, PIPELINE_REC);
411 ret != destroyPipeline(data, PIPELINE_PLAY);
415 static gboolean destroyPipeline(AppData *data, PipeLineType type)
419 GstElement *pipeline = NULL;
421 ULOG_INFO("%s() - Stopping playback/recording", G_STRFUNC);
426 pipeline = data->recPipeline;
428 data->recPipeline = NULL;
433 pipeline = data->playPipeline;
435 data->playPipeline = NULL;
440 if (!GST_IS_ELEMENT(pipeline))
443 /* this unallocates everything */
444 gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
446 /* for some reason the state does not update manually */
447 gst_element_get_state(pipeline, &state,
448 &pending, GST_CLOCK_TIME_NONE);
449 pipelineStateChanged(pipeline,
456 gst_object_unref(pipeline);
465 static void pipelineStateChanged (GstElement *element,
471 g_assert(NULL != data);
475 case GST_STATE_PLAYING:
476 if(APPSTATE_RECORDING == getAppState(data))
478 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_RECORDING);
479 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
482 ULOG_INFO("%s() - Recording", G_STRFUNC);
483 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
484 RECORDER_MSG_RECORDING);
486 gtk_widget_set_state(data->buttonRec, GTK_STATE_ACTIVE);
488 if (data->recUpdateId == 0 && gettimeofday(&data->recStartTv, NULL) == 0)
490 data->recUpdateId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, REC_UPDATE_INTERVAL, (GSourceFunc) cbUpdateRecLength, data, NULL);
495 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_PLAYING);
496 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
499 ULOG_INFO("%s() - Playing", G_STRFUNC);
500 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
501 RECORDER_MSG_PLAYING);
502 gtk_widget_set_state(data->buttonPlay, GTK_STATE_ACTIVE);
504 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PAUSE);
510 case GST_STATE_READY:
511 /* hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, "Ready..."); */
512 ULOG_INFO("%s() - Ready", G_STRFUNC);
513 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
517 case GST_STATE_PAUSED:
520 GstFormat fmt = GST_FORMAT_TIME;
521 ULOG_INFO("%s() - Paused", G_STRFUNC);
523 /* if pipeline pos == 0 => stopped, else => paused */
524 if (GST_IS_ELEMENT(data->playPipeline) && gst_element_query_position(data->playPipeline, &fmt, &pos) && pos != 0)
526 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_PAUSED);
527 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
528 RECORDER_MSG_PAUSED);
530 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
531 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
536 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
537 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
538 RECORDER_MSG_STOPPED);
539 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
540 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
542 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
547 ULOG_INFO("%s() - Null", G_STRFUNC);
548 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
549 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
551 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
552 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
553 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
558 ULOG_WARN("%s() - default case", G_STRFUNC);
564 static gboolean cbBus(GstBus *bus,
568 AppData *app = (AppData*)data;
570 switch (GST_MESSAGE_TYPE(message))
572 case GST_MESSAGE_WARNING:
577 gst_message_parse_error (message, &err, &debug);
578 ULOG_WARN("%s() - Warning: %s", G_STRFUNC, err->message);
584 case GST_MESSAGE_ERROR:
589 gst_message_parse_error (message, &err, &debug);
590 ULOG_ERR("%s() - Error: %s", G_STRFUNC, err->message);
594 /* flow through to eos */
597 case GST_MESSAGE_EOS:
599 ULOG_INFO("%s() - eos", G_STRFUNC);
601 switch(getAppState(app))
603 case APPSTATE_PLAYING:
604 /* stop playback after a short break*/
605 g_timeout_add(STOP_DELAY, (GSourceFunc)cbStopPlayback, data);
608 case APPSTATE_RECORDING:
609 gst_element_set_state(GST_ELEMENT(app->recPipeline),
611 destroyPipeline(app, PIPELINE_REC);
617 /* destroyPipelines(app); */
623 case GST_MESSAGE_STATE_CHANGED:
629 gst_message_parse_state_changed(message, &old, &new, &pending);
631 pipelineStateChanged(NULL, old, new, pending, app);
637 /* unhandled message */
638 ULOG_WARN("%s() - Unhandled message, type = %d", G_STRFUNC, message->type);
642 /* remove message from the queue */
646 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data)
652 app = (AppData *) data;
657 destroyPipelines(app);
658 if (app->playPipeline)
659 gst_object_unref(GST_OBJECT(app->playPipeline));
661 if (app->recPipeline)
662 gst_object_unref(GST_OBJECT(app->recPipeline));
667 static gboolean cbCheckPosition (AppData *data)
669 GstFormat fmt = GST_FORMAT_TIME;
670 gint64 pos = 0, len = 0;
671 static gboolean lengthSet = FALSE;
673 g_assert(NULL != data);
676 if(!lengthSet && gst_element_query_duration(data->playPipeline, &fmt, &len))
681 size = GST_TIME_TO_SECS(len);
682 setLength(data, size); /* sets lengthEntry and adjustment */
687 /* calculate position */
688 if (gst_element_query_position(data->playPipeline, &fmt, &pos))
690 gdouble time = GST_TIME_TO_SECS(pos);
692 ULOG_DEBUG("pos = %lld, time = %f",
697 gtk_adjustment_set_value(
698 GTK_ADJUSTMENT(data->mainViewData.adjustment),
700 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
703 if (APPSTATE_PLAYING == getAppState(data))
711 static void cbNew(GtkWidget* widget, AppData *data)
713 g_assert(NULL != data);
715 if (!closeFile(data))
718 /* remove pipelines if existing */
719 destroyPipelines(data);
720 ULOG_DEBUG_F("cbNew");
721 /* destroy tmp file */
723 /* clear filenames */
724 g_free(data->openFileName);
725 data->openFileName = NULL;
726 g_free(data->saveFileName);
727 data->saveFileName = NULL;
728 /* data->filter = FORMAT_NONE;*/
729 data->file_format = FORMAT_NONE;
732 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
733 RECORDER_FILE_UNTITLED);
734 setLength(data, 0.0);
735 /* update the display + scale */
736 gtk_adjustment_set_value(GTK_ADJUSTMENT(data->mainViewData.adjustment),
738 gtk_widget_set_sensitive(data->buttonSave, FALSE);
739 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
742 gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
744 ULOG_DEBUG_F("cbNew end");
747 static void cbOpen(GtkWidget* widget, AppData *data)
749 GtkWidget* dialog = NULL;
750 gchar *tmpfile = NULL;
751 gchar *selected = NULL;
756 GtkFileFilter *filter;
759 ULOG_DEBUG_F("begin");
760 g_assert(NULL != data);
762 if (!closeFile(data))
767 filter = gtk_file_filter_new();
768 gtk_file_filter_add_mime_type(filter, "audio/x-mp3");
771 g_assert(GTK_IS_WINDOW(data->mainView));
773 dialog = hildon_file_chooser_dialog_new_with_properties(
774 GTK_WINDOW(data->mainView),
775 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
776 "file-system-model", NULL,
782 gtk_widget_show_all(dialog);
784 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
786 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
789 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
791 if (dialog != NULL && GTK_IS_WIDGET(dialog))
793 gtk_widget_destroy(dialog);
795 ULOG_DEBUG("%s() - dialog destroyed", G_STRFUNC);
799 if (NULL == selected) /* no file selected */
802 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
804 if (openFile(selected, &format, &tmpfile))
806 ULOG_INFO("%s() - openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
810 /* update filenames */
811 basename = g_path_get_basename(selected);
813 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
814 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
817 g_free(data->openFileName);
818 data->openFileName = tmpfile;
819 data->file_format = format;
820 data->filter = format;
821 g_free(data->saveFileName);
822 data->saveFileName = NULL;
823 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
825 len = guessMediaLength(data);
827 setLength(data, len);
829 setLength(data, 0.0);
835 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
836 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
845 openURI(gpointer user_data)
849 gchar *selected = NULL;
851 gchar *tmpfile = NULL;
852 gchar *basename = NULL;
856 data = (AppData *) user_data;
858 if (NULL == data->mimeURI)
861 uri = gnome_vfs_uri_new(data->mimeURI);
862 selected = g_strdup(gnome_vfs_uri_get_path(uri));
864 gnome_vfs_uri_unref(uri);
867 g_free(data->mimeURI);
868 data->mimeURI = NULL;
870 /* TODO: the following is duplicated in cbOpen(), move to a tryOpen() function ? */
872 if (NULL == selected)
875 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
877 if (openFile(selected, &format, &tmpfile))
879 ULOG_INFO("%s: openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
883 /* update filenames */
884 basename = g_path_get_basename(selected);
886 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
887 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
890 g_free(data->openFileName);
891 data->openFileName = tmpfile;
892 data->file_format = format;
893 data->filter = format;
894 g_free(data->saveFileName);
895 data->saveFileName = NULL;
896 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
898 len = guessMediaLength(data);
900 setLength(data, len);
902 setLength(data, 0.0);
908 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
909 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
917 static void openPlayPipeline( AppData *data )
920 GstFormat fmt = GST_FORMAT_TIME;
923 /* create pipelines */
924 /* check file type */
925 switch (data->file_format)
932 destroyPipelines(data);
933 data->filter = data->file_format;
934 createPipeline(data, PIPELINE_PLAY);
938 destroyPipelines(data);
939 data->filter = data->file_format;
940 createPipeline(data, PIPELINE_PLAY_MP3);
945 ULOG_WARN("%s() - unknown file_format", G_STRFUNC);
946 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Unknown filetype!"));
951 if (!GST_IS_ELEMENT(data->playPipeline))
953 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline!"));
957 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_READY);
958 gst_element_get_state(GST_ELEMENT(data->playPipeline), NULL, NULL, GST_CLOCK_TIME_NONE /* or ns */);
960 /* calculate length */
961 if (gst_element_query_duration (data->playPipeline, &fmt, &len))
965 size = GST_TIME_TO_SECS(len);
966 ULOG_INFO("playSize: len:%lld size:%f", len, size);
967 setLength(data, size);
973 ULOG_INFO("playSize else");
974 setLength(data, 0.0);
979 /* returns whether the action can proceed or should be aborted */
981 closeFile(AppData *data)
989 note = hildon_note_new_confirmation_add_buttons(GTK_WINDOW(data->mainView), _("Save recording?"),
990 _("Yes"), GTK_RESPONSE_YES,
991 _("No"), GTK_RESPONSE_NO,
992 _("Cancel"), GTK_RESPONSE_CANCEL,
995 i = gtk_dialog_run(GTK_DIALOG(note));
996 gtk_widget_destroy(note);
1000 case GTK_RESPONSE_CANCEL:
1003 case GTK_RESPONSE_NO:
1006 case GTK_RESPONSE_YES:
1008 cbSaveAs(NULL, data);
1012 ULOG_WARN("%s(): unknown response from dialog: %d", G_STRFUNC, i);
1018 static void cbSave(GtkWidget* widget, AppData *data)
1020 GtkWidget* dialog = NULL;
1021 const gchar *current;
1022 gchar *selected = NULL;
1026 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1028 current = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1029 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1031 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1035 /* if saveFileName does not exist run saveas */
1036 if (NULL == data->saveFileName)
1039 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1040 GTK_WINDOW(data->mainView),
1041 GTK_FILE_CHOOSER_ACTION_SAVE));
1044 gtk_widget_show_all(dialog);
1046 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1048 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1051 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1053 gtk_widget_destroy(dialog);
1055 if (NULL != selected)
1057 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC,
1059 g_free(data->saveFileName);
1060 data->saveFileName = g_strdup_printf("%s%s", selected, getExtension(data->file_format));
1071 if (doSave(gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry)), data->saveFileName, data->file_format))
1073 gchar *basename = g_path_get_basename(data->saveFileName);
1074 ULOG_INFO("%s() - file succesfully saved!", G_STRFUNC);
1075 g_free(data->openFileName);
1076 data->openFileName = g_strdup(data->saveFileName);
1078 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1079 data->saveFileName);
1080 gtk_widget_set_sensitive(data->buttonSave, FALSE);
1081 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
1085 ULOG_DEBUG("%s() - end", G_STRFUNC);
1089 static void cbSettings(GtkWidget* widget, AppData *data)
1091 settings_edit( widget, data );
1094 static void cbEmailing(GtkWidget* widget, AppData *data)
1097 GSList *list = NULL;
1099 g_assert(NULL != data);
1101 file = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1102 if ( g_file_test( file, G_FILE_TEST_EXISTS ) )
1104 ULOG_INFO("Emailing: %s", file);
1105 list= g_slist_append( list , file );
1106 osso_email_files_email( data->osso, list );
1112 static void cbSaveAs(GtkWidget* widget, AppData *data)
1114 GtkWidget* dialog = NULL;
1115 const gchar *current;
1116 gchar *selected = NULL;
1118 g_assert(NULL != data);
1120 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1122 current = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1123 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1125 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1130 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1131 GTK_WINDOW(data->mainView),
1132 GTK_FILE_CHOOSER_ACTION_SAVE));
1134 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog),
1135 get_default_dir() );
1138 gtk_widget_show_all(dialog);
1140 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1142 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1145 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1146 gtk_widget_destroy(dialog);
1148 if (NULL == selected)
1151 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
1153 g_free(data->saveFileName);
1154 data->saveFileName = NULL;
1156 if (saveFile(selected, data->openFileName, data->file_format, &(data->saveFileName)))
1161 g_assert(data->saveFileName);
1163 /* set new title that has the file name */
1164 basename = g_path_get_basename(data->saveFileName);
1165 ULOG_DEBUG("%s() - file '%s' succesfully saved!", G_STRFUNC, data->saveFileName);
1167 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
1169 /* Houston, we have a kludge:
1170 * for AU files we need to keep the old tmpfile for playback
1171 * for RAW/iLBC files, we can remove the tmpfile and point openFileName to the saved file
1173 ext = getExtension(data->file_format);
1174 if (strcmp(ext, EXTENSION_AU) != 0)
1176 g_free(data->openFileName);
1177 data->openFileName = g_strdup(data->saveFileName);
1180 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1181 data->saveFileName);
1188 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Saving file failed!"));
1194 ULOG_DEBUG("%s() - end", G_STRFUNC);
1197 static void cbRec(GtkWidget* widget, AppData *data)
1199 g_assert(NULL != data);
1201 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1203 if (APPSTATE_READY != getAppState(data))
1205 ULOG_WARN("%s() - state different than READY -> return", G_STRFUNC);
1209 if (!closeFile(data))
1212 /* clear filenames, use tmp file */
1213 g_free(data->openFileName);
1214 data->openFileName = NULL;
1216 g_free(data->saveFileName);
1217 data->saveFileName = NULL;
1219 switch (data->filter)
1222 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1223 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1227 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1228 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1232 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1233 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1237 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1238 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1243 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1244 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1248 ULOG_INFO("%s() - creating pipelines", G_STRFUNC);
1249 /* start recording */
1250 /* create related pipelines */
1251 if (createPipeline(data, PIPELINE_REC))
1253 ULOG_INFO("%s() - starting recording", G_STRFUNC);
1254 /* start recording */
1255 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1258 /* update display */
1259 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1260 data->saveFileName);
1262 setAppState(data, APPSTATE_RECORDING);
1263 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1264 gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
1265 data->file_format = data->filter;
1269 ULOG_ERR("Could not create rec pipeline!");
1270 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline"));
1271 setAppState(data, APPSTATE_READY);
1274 ULOG_DEBUG("%s() - end", G_STRFUNC);
1277 static void cbPlay(GtkWidget* widget, AppData *data)
1279 const gchar * file = NULL;
1281 g_assert(NULL != data);
1283 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1285 file = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1286 if (NULL == data->openFileName || NULL == file || strcmp(file, RECORDER_FILE_UNTITLED) == 0)
1288 ULOG_WARN("%s() - nothing to play", G_STRFUNC);
1292 openPlayPipeline(data);
1294 if (APPSTATE_PLAYING == getAppState(data))
1296 if (GST_IS_ELEMENT(data->playPipeline))
1298 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_PAUSED);
1299 setAppState(data, APPSTATE_READY);
1304 if (APPSTATE_READY != getAppState(data))
1306 ULOG_WARN("%s() - state different than PLAYING or READY -> return", G_STRFUNC);
1310 ULOG_INFO("filename %s", file);
1312 /*openPlayPipeline( data );*/
1314 /*if ( ! GST_IS_ELEMENT(data->playPipeline) )
1316 if (g_strrstr(data->openFileName, EXTENSION_RAW))
1318 ULOG_INFO("cbOpen() - file was raw, assuming audio/x-raw-int, 8kHz, 1 ch, 16-bit");
1319 destroyPipelines(data);
1320 createPipeline(data, PIPELINE_PLAY);
1324 if (! GST_IS_ELEMENT(data->playPipeline))
1326 ULOG_WARN("%s() - playPipeline does not exist", G_STRFUNC);
1330 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1333 setAppState(data, APPSTATE_PLAYING);
1335 g_timeout_add(PLAY_UPDATE_INTERVAL, (GSourceFunc)cbCheckPosition, data);
1337 ULOG_DEBUG("%s() - end", G_STRFUNC);
1340 static void cbStop(GtkWidget* widget, AppData *data)
1342 g_assert(NULL != data);
1344 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1346 /* check if we are playing/recording */
1349 if (APPSTATE_PLAYING != getAppState(data) &&
1350 APPSTATE_RECORDING != getAppState(data))
1352 ULOG_WARN("cbStop() - state different than PLAYING or RECORDING "
1358 /* stop playing or recording */
1359 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
1360 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1361 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
1363 /* destroy related pipeline */
1364 switch(getAppState(data))
1366 case APPSTATE_PLAYING:
1367 /* don't destroy the playing pipeline. Instead, set the pipeline to PAUSED */
1368 /* destroyPipeline(data, PIPELINE_PLAY); */
1369 ULOG_INFO("%s() - Setting playPipeline state to PAUSED", G_STRFUNC);
1370 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1373 case APPSTATE_READY:
1374 /* seek to zero, but not for PCM pipeline */
1375 /* if (data->playPipelineType == PIPELINE_PLAY || seekToZero(data, GST_ELEMENT(data->playPipeline))) */
1376 if ( !GST_IS_ELEMENT(data->playPipeline) || seekToZero(data, GST_ELEMENT(data->playPipeline)))
1378 gtk_adjustment_set_value(
1379 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1380 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1381 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
1382 RECORDER_MSG_STOPPED);
1386 case APPSTATE_RECORDING:
1389 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1391 destroyPipeline(data, PIPELINE_REC);
1392 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1393 data->saved = FALSE;
1395 len = guessMediaLength(data);
1397 setLength(data, len);
1403 /* seekToZero(data, GST_ELEMENT(data->playPipeline)); */
1404 /* should not come here */
1408 setAppState(data, APPSTATE_READY);
1410 ULOG_DEBUG("%s() - end", G_STRFUNC);
1414 /* ui construction functions */
1416 static GtkWidget* createToolBar(AppData *data)
1418 GtkToolbar* toolBar = NULL;
1420 GtkToolItem* new = NULL;
1421 GtkToolItem* open = NULL;
1422 GtkToolItem* save = NULL;
1423 GtkToolItem* saveas = NULL;
1424 GtkToolItem* sep = NULL;
1425 GtkToolItem* play = NULL;
1426 GtkToolItem* rec = NULL;
1427 GtkToolItem* stop = NULL;
1429 /* create buttons */
1430 new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
1431 open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
1432 save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
1433 data->buttonSave = GTK_WIDGET(save);
1434 saveas = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE_AS);
1435 data->buttonSaveAs = GTK_WIDGET(saveas);
1436 gtk_widget_set_sensitive(data->buttonSave, FALSE);
1437 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
1440 rec = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_RECORD);
1441 data->buttonRec = GTK_WIDGET(rec);
1442 play = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
1443 data->buttonPlay = GTK_WIDGET(play);
1444 stop = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
1446 /* create separator */
1447 sep = gtk_separator_tool_item_new();
1449 /* create the toolbar itself */
1450 toolBar = GTK_TOOLBAR(gtk_toolbar_new());
1452 /* add items to toolbar */
1453 gtk_toolbar_insert(toolBar, new, -1);
1454 gtk_toolbar_insert(toolBar, open, -1);
1456 gtk_toolbar_insert(toolBar, save, -1);
1458 gtk_toolbar_insert(toolBar, saveas, -1);
1459 gtk_toolbar_insert(toolBar, sep, -1);
1460 gtk_toolbar_insert(toolBar, rec, -1);
1461 gtk_toolbar_insert(toolBar, play, -1);
1462 gtk_toolbar_insert(toolBar, stop, -1);
1464 /* connect signals */
1465 g_signal_connect(G_OBJECT(new), "clicked",
1468 g_signal_connect(G_OBJECT(open), "clicked",
1472 g_signal_connect(G_OBJECT(save), "clicked",
1476 g_signal_connect(G_OBJECT(saveas), "clicked",
1477 G_CALLBACK(cbSaveAs),
1479 g_signal_connect(G_OBJECT(rec), "clicked",
1482 g_signal_connect(G_OBJECT(play), "clicked",
1485 g_signal_connect(G_OBJECT(stop), "clicked",
1489 return GTK_WIDGET(toolBar);
1493 static void cbItemGroupChanged( gpointer data )
1495 AppData* app = (AppData* ) data;
1496 GValue active ={G_TYPE_INVALID};
1499 g_value_init(&active, G_TYPE_INT);
1501 g_object_get_property(G_OBJECT(app->radio_pcma), "active", &active);
1502 pcma = g_value_get_int(&active);
1503 g_object_get_property(G_OBJECT(app->radio_ilbc), "active", &active);
1504 ilbc = g_value_get_int(&active);
1505 g_object_get_property(G_OBJECT(app->radio_pcm), "active", &active);
1506 pcm = g_value_get_int(&active);
1508 ULOG_INFO("change type pcma=%d ilbc=%d pcm=%d",pcma, ilbc, pcm);
1510 app->filter = FORMAT_PCMA;
1511 else if ( ilbc == 1 )
1512 app->filter = FORMAT_ILBC;
1513 else if ( pcm == 1 )
1514 app->filter = FORMAT_WAV;
1518 ULOG_INFO("filter type=%d", app->filter);
1521 static void cbItemClose(GtkWidget *widget, gpointer data)
1525 if (!closeFile(data))
1531 /* Create the menu items needed for the main view */
1532 static void createMenu( AppData *data )
1534 /* Create needed variables */
1535 GSList *group = NULL;
1537 GtkWidget *menu_file;
1538 GtkWidget *menu_others;
1539 GtkWidget *item_file;
1540 GtkWidget *item_file_open;
1541 GtkWidget *item_file_save_as;
1542 GtkWidget *item_others;
1543 GtkWidget *item_pcma;
1544 GtkWidget *item_pcmu;
1545 GtkWidget *item_ilbc;
1546 GtkWidget *item_pcm;
1547 GtkWidget *item_settings;
1548 GtkWidget *item_email;
1550 GtkWidget *item_radio_type1;
1552 GtkWidget *item_close;
1553 GtkWidget *item_separator;
1555 /* Get the menu from view */
1556 main_menu = GTK_MENU(gtk_menu_new());
1557 hildon_window_set_menu(data->mainView, main_menu);
1559 /* Create new submenu for "Others" */
1560 menu_file = gtk_menu_new ();
1561 menu_others = gtk_menu_new ();
1563 /* Create menu items */
1564 item_file = gtk_menu_item_new_with_label (_("File"));
1565 item_file_open = gtk_menu_item_new_with_label(_("Open..."));
1566 item_file_save_as = gtk_menu_item_new_with_label(_("Save as..."));
1567 item_others = gtk_menu_item_new_with_label (_("Recording format"));
1568 item_settings = gtk_menu_item_new_with_label (_("Settings"));
1569 item_email = gtk_menu_item_new_with_label(_("Send via e-mail..."));
1571 item_pcma = gtk_radio_menu_item_new_with_label(
1572 group, FORMAT_NAME_PCMA);
1573 item_ilbc = gtk_radio_menu_item_new_with_label_from_widget(
1574 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_ILBC);
1575 item_pcmu = gtk_radio_menu_item_new_with_label_from_widget(
1576 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_PCMU);
1577 item_pcm = gtk_radio_menu_item_new_with_label_from_widget(
1578 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_WAV);
1580 data->filter = get_default_filter();
1582 if (data->filter == FORMAT_ILBC)
1583 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_ilbc), TRUE);
1584 else if (data->filter == FORMAT_WAV)
1585 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_pcm), TRUE);
1586 else if (data->filter == FORMAT_PCMA)
1587 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_pcma), TRUE);
1590 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_ilbc), TRUE);
1591 data->filter = FORMAT_ILBC;
1594 data->radio_pcma = item_pcma;
1595 data->radio_ilbc = item_ilbc;
1596 data->radio_pcm = item_pcm;
1598 data->radiotype = item_radio_type1;
1600 item_close = gtk_menu_item_new_with_label(_("Close"));
1601 item_separator = gtk_separator_menu_item_new();
1603 /* Add menu items to right menus */
1604 gtk_menu_append( main_menu, item_file );
1605 gtk_menu_append( menu_file, item_file_open );
1606 gtk_menu_append( menu_file, item_file_save_as );
1607 gtk_menu_append( menu_file, item_email );
1608 gtk_menu_append( main_menu, item_others );
1609 gtk_menu_append( menu_others, item_pcm );
1610 gtk_menu_append( menu_others, item_pcma );
1611 gtk_menu_append( menu_others, item_ilbc);
1613 gtk_menu_append( main_menu, item_settings );
1615 gtk_menu_append( main_menu, item_close );
1617 /* Add others submenu to the "Others" item */
1618 gtk_menu_item_set_submenu(
1619 GTK_MENU_ITEM(item_file), menu_file );
1620 gtk_menu_item_set_submenu(
1621 GTK_MENU_ITEM(item_others), menu_others );
1623 /* Attach the callback functions to the activate signal */
1624 g_signal_connect( G_OBJECT( item_file_open), "activate",
1625 GTK_SIGNAL_FUNC (cbOpen), data);
1626 g_signal_connect( G_OBJECT( item_file_save_as), "activate",
1627 GTK_SIGNAL_FUNC (cbSaveAs), data);
1628 g_signal_connect( G_OBJECT( item_settings ), "activate",
1629 GTK_SIGNAL_FUNC (cbSettings), data);
1630 g_signal_connect( G_OBJECT( item_email ), "activate",
1631 GTK_SIGNAL_FUNC (cbEmailing), data);
1633 g_signal_connect( G_OBJECT( item_close ), "activate",
1634 GTK_SIGNAL_FUNC (cbItemClose), data);
1636 g_signal_connect_swapped(G_OBJECT(item_pcma), "activate", G_CALLBACK(cbItemGroupChanged), data);
1637 g_signal_connect_swapped(G_OBJECT(item_pcm), "activate", G_CALLBACK(cbItemGroupChanged), data);
1639 /* Make all menu widgets visible */
1641 gtk_widget_show_all( GTK_WIDGET( main_menu ) );
1644 gboolean maemo_recorder_ui_new(AppData *data)
1646 HildonProgram *app = NULL;
1647 HildonWindow *window = NULL;
1648 GtkWidget *hbox = NULL;
1649 GtkWidget *vbox = NULL;
1650 GtkWidget *label = NULL;
1651 GtkWidget *entry1 = NULL;
1652 GtkWidget *entry2 = NULL;
1653 GtkWidget *entry3 = NULL;
1654 GtkWidget *toolBar = NULL;
1655 GtkWidget *table = NULL;
1656 GtkWidget *scale = NULL;
1657 GtkObject *adjustment = NULL;
1659 g_assert(NULL != data);
1661 app = HILDON_PROGRAM(hildon_program_get_instance());
1662 g_set_application_name(RECORDER_APP_TITLE);
1665 window = HILDON_WINDOW(hildon_window_new());
1667 hildon_program_add_window(app, window);
1669 /* content for main view */
1671 /* create vbox, divides control area and view area */
1672 vbox = gtk_vbox_new(FALSE, 0);
1674 /* create hbox to divide control area */
1675 hbox = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
1677 /* create toolbar */
1678 toolBar = createToolBar(data);
1680 /* create table for labels */
1681 table = gtk_table_new (4, 3, FALSE);
1682 gtk_table_set_homogeneous(GTK_TABLE(table), FALSE);
1684 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
1685 gtk_table_set_col_spacings (GTK_TABLE (table), 0);
1687 label = gtk_label_new_with_mnemonic(_("Filename:"));
1689 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1691 gtk_table_attach_defaults (GTK_TABLE (table),
1695 entry1 = gtk_entry_new ();
1696 gtk_entry_set_has_frame(GTK_ENTRY(entry1), FALSE);
1697 gtk_entry_set_text (GTK_ENTRY (entry1), _(RECORDER_FILE_UNTITLED));
1698 gtk_table_attach_defaults (GTK_TABLE (table), entry1, 1, 3, 0, 1);
1699 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry1);
1701 label = gtk_label_new_with_mnemonic (_("Length:"));
1703 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1705 gtk_table_attach_defaults (GTK_TABLE (table),
1709 entry2 = gtk_entry_new ();
1710 gtk_entry_set_has_frame(GTK_ENTRY(entry2), FALSE);
1711 gtk_entry_set_text (GTK_ENTRY (entry2), "0:00.00");
1712 gtk_table_attach_defaults (GTK_TABLE (table), entry2, 1, 3, 1, 2);
1713 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry2);
1715 label = gtk_label_new_with_mnemonic (_("State:"));
1717 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1719 gtk_table_attach_defaults (GTK_TABLE (table),
1723 entry3 = gtk_entry_new ();
1724 gtk_entry_set_has_frame(GTK_ENTRY(entry3), FALSE);
1725 gtk_entry_set_text (GTK_ENTRY (entry3), RECORDER_MSG_READY);
1726 gtk_table_attach_defaults (GTK_TABLE (table), entry3, 1, 3, 2, 3);
1727 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry3);
1729 adjustment = gtk_adjustment_new (0.00,
1736 scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1738 /* gtk_table_attach_defaults (GTK_TABLE (table),
1742 /* connect signals */
1743 g_signal_connect(G_OBJECT(adjustment), "value-changed", G_CALLBACK(cbUserSeek), data);
1744 g_signal_connect(G_OBJECT(scale), "format-value", G_CALLBACK(cbFormatSeekbarValue), data);
1745 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(cbDestroy), data);
1747 /* packing the view */
1748 gtk_container_add (GTK_CONTAINER(window), vbox);
1749 gtk_box_pack_start (GTK_BOX(vbox), table, FALSE, TRUE, 0);
1750 gtk_box_pack_start (GTK_BOX(vbox), scale, FALSE, FALSE, 0);
1751 /* gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 0); */
1753 hildon_window_add_toolbar(window, GTK_TOOLBAR(toolBar));
1755 /* initialise the ui */
1756 gtk_entry_set_editable(GTK_ENTRY(entry1), FALSE);
1757 gtk_entry_set_editable(GTK_ENTRY(entry2), FALSE);
1758 gtk_entry_set_editable(GTK_ENTRY(entry3), FALSE);
1760 /* store needed widgets */
1762 data->mainView = window;
1763 data->mainViewData.toolBar = GTK_WIDGET(toolBar);
1764 data->mainViewData.fileNameEntry = GTK_WIDGET(entry1);
1765 data->mainViewData.lengthEntry = GTK_WIDGET(entry2);
1766 data->mainViewData.stateEntry = GTK_WIDGET(entry3);
1767 data->mainViewData.adjustment = GTK_OBJECT(adjustment);
1770 gtk_widget_show_all(GTK_WIDGET(window));
1778 maemo_recorder_mime_open(gpointer user_data, gint argc, gchar **argv)
1782 ULOG_DEBUG("%s with %d arguments", __FUNCTION__, argc);
1787 g_assert(user_data);
1788 data = (AppData *) user_data;
1790 if (argv[0] != NULL)
1792 ULOG_DEBUG("request to open %s", argv[0]);
1793 g_free(data->mimeURI);
1794 data->mimeURI = g_strdup(argv[0]);
1795 g_idle_add(openURI, (gpointer) data);
1796 gtk_window_present(GTK_WINDOW(data->mainView));
1800 static void seekToTime(GstElement *pipeline, gdouble secs)
1802 g_assert(NULL != pipeline);
1803 ULOG_DEBUG("Seeking to: %.2f", secs);
1805 /* time must be nanoseconds */
1806 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1807 GST_SEEK_TYPE_SET, (gint64) (secs * GST_SECOND),
1808 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1810 ULOG_WARN("seekToTime failed!");
1813 ULOG_DEBUG("seekToTime succeeded");
1816 static gboolean seekToZero(AppData *data, GstElement *pipeline)
1819 g_assert(NULL != pipeline);
1820 ULOG_DEBUG("Seeking to zero");
1822 /* time must be nanoseconds */
1823 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1824 GST_SEEK_TYPE_SET, (gint64) 0,
1825 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1827 ULOG_ERR("seekToZero failed! Trying to destroy and re-create pipeline");
1828 plType = data->playPipelineType;
1830 /* gst_element_set_state(pipeline, GST_STATE_READY); */
1831 destroyPipeline(data, plType);
1832 return createPipeline(data, plType);
1835 ULOG_DEBUG("seekToZero succeeded");
1839 static void setLength(AppData *data, gdouble secs)
1849 g_object_set(G_OBJECT(data->mainViewData.adjustment),
1852 gtk_adjustment_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1858 secs -= mins * 60.0;
1861 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
1864 ULOG_INFO("Setting length to %s", tmp);
1866 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
1871 static gdouble guessMediaLength(AppData *data)
1873 GnomeVFSFileSize size = 0;
1874 gdouble bitrate = 0.0;
1877 if (data->openFileName)
1878 size = getFileLength(data->openFileName);
1885 ULOG_DEBUG("file size: %llu bytes", size);
1887 switch (data->file_format)
1890 bitrate = ILBC_BITRATE_20;
1895 bitrate = PCMA_BITRATE;
1905 len = (((gdouble) size) * 8.0) / (bitrate);
1906 ULOG_DEBUG("guessed media length: %.2f secs", len);
1911 static GstCaps *createCapsFilter(AudioFormat format)
1916 return gst_caps_new_simple(
1918 "rate", G_TYPE_INT, ILBC_RATE,
1919 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1920 "mode", G_TYPE_INT, 20, /* 20 ms frames */
1923 return gst_caps_new_simple(
1925 "rate", G_TYPE_INT, DEFAULT_RATE,
1926 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1929 return gst_caps_new_simple(
1931 "rate", G_TYPE_INT, DEFAULT_RATE,
1932 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1936 return gst_caps_new_simple(
1938 "rate", G_TYPE_INT, PCM_RATE,
1939 "signed", G_TYPE_BOOLEAN, TRUE,
1940 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1941 "endianness", G_TYPE_INT, PCM_ENDIANNESS,
1942 "width", G_TYPE_INT, PCM_WIDTH,
1943 "depth", G_TYPE_INT, PCM_DEPTH,
1946 ULOG_WARN("%s(): creating ANY caps", G_STRFUNC);
1947 return gst_caps_new_any();
1951 static gboolean cbStopPlayback(AppData *data)
1954 ULOG_INFO("Stopping playback");
1956 g_assert(data != NULL);
1958 ret = gst_element_set_state(GST_ELEMENT(data->playPipeline),
1960 if (seekToZero(data, GST_ELEMENT(data->playPipeline)))
1962 gtk_adjustment_set_value(
1963 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1964 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1966 setAppState(data, APPSTATE_READY);
1967 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
1968 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1973 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data)
1975 /*ULOG_INFO("cbUserSeek");*/
1978 g_return_if_fail(data != NULL);
1979 app = (AppData *) data;
1981 if (getAppState(app) != APPSTATE_READY || NULL == app->playPipeline)
1984 seekToTime(app->playPipeline, gtk_adjustment_get_value(adjustment));
1987 static gchar *cbFormatSeekbarValue(GtkScale *scale, gdouble value)
1989 /* ULOG_INFO("cbFormatSeekbarValue");*/
1991 gint digits = gtk_scale_get_digits(scale);
1996 value -= mins * 60.0;
1997 return g_strdup_printf("%d:%0*.*f", mins, digits + 3, digits, value);
2000 return g_strdup_printf("%0.*f", digits, value);
2003 static gboolean cbUpdateRecLength(AppData *data)
2010 if (gettimeofday(&tv, NULL) != 0)
2013 secs = tv.tv_sec - data->recStartTv.tv_sec;
2014 secs += ((tv.tv_usec - data->recStartTv.tv_usec) / 1000000.0);
2019 secs -= mins * 60.0;
2020 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
2023 tmp = g_strdup_printf("%0.2f", secs);
2025 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
2029 if (getAppState(data) == APPSTATE_RECORDING)
2032 data->recUpdateId = 0;