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
24 #include <glib/gi18n-lib.h>
25 #include <libgnomevfs/gnome-vfs.h>
27 #include <hildon-widgets/hildon-program.h>
28 #include <hildon-widgets/hildon-note.h>
29 #include <hildon-widgets/hildon-banner.h>
30 #include <hildon-widgets/hildon-defines.h>
31 #include <hildon-widgets/hildon-file-system-model.h>
32 #include <hildon-widgets/hildon-file-chooser-dialog.h>
35 #include <osso-helplib.h>
36 #include <ossoemailinterface.h>
38 #include "maemo-recorder.h"
39 #include "maemo-recorder-ui.h"
40 #include "maemo-recorder-file.h"
43 #define DEFAULT_REC_BLOCKSIZE "160"
45 #define STOP_DELAY 500
46 #define REC_UPDATE_INTERVAL 750
47 #define PLAY_UPDATE_INTERVAL 200
51 #define GST_TIME_MINS(t) \
52 (guint) ((((GstClockTime)(t)) / (GST_SECOND * 60)) % 60)
53 #define GST_TIME_SECS(t) \
54 (guint) ((((GstClockTime)(t)) / GST_SECOND) % 60)
55 #define GST_TIME_TO_SECS(t) \
56 (gdouble) (((gdouble)(t)) / (gdouble) GST_SECOND) /* GST_SECOND should be 1e9 */
57 #define GST_TIME_MSECS(t) \
58 (guint) (((GstClockTime)(t)) % GST_SECOND)
60 #define RECORDER_APP_TITLE "Maemo Recorder"
61 #define RECORDER_MSG_READY _("Ready")
62 #define RECORDER_MSG_STOPPED _("Stopped")
63 #define RECORDER_MSG_PAUSED _("Paused")
64 #define RECORDER_MSG_PLAYING _("Playing")
65 #define RECORDER_MSG_RECORDING _("Recording")
66 #define RECORDER_FILE_UNTITLED _("Untitled")
68 #define RECORDER_FMT_STRING_NONE _("N/A")
70 /* general enumerations */
85 /* function prototypes */
87 static gboolean cbBus (GstBus *bus,
91 static void pipelineStateChanged (GstElement *element,
97 static void seekToTime(GstElement *pipeline, gdouble secs);
98 static gboolean seekToZero(AppData *data, GstElement *pipeline);
99 static void setLength(AppData *data, gdouble secs);
100 static void setFormatString(AppData *data, AudioFormat afmt);
101 static gboolean cbStopPlayback(AppData *data);
102 static void cbStop(GtkWidget* widget, AppData *data);
103 static void cbPlay(GtkWidget* widget, AppData *data);
104 static void cbRec(GtkWidget* widget, AppData *data);
105 static void cbNew(GtkWidget* widget, AppData *data);
106 static void cbOpen(GtkWidget* widget, AppData *data);
107 /*static void cbSave(GtkWidget* widget, AppData *data);*/
108 static void cbSaveAs(GtkWidget* widget, AppData *data);
109 static void cbItemClose(GtkWidget *widget, gpointer data);
110 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data);
111 static gchar* cbFormatSeekbarValue(GtkScale *scale, gdouble value);
112 static GtkWidget* createToolBar(AppData *data);
113 static void createMenu( AppData *data );
114 static gboolean createPipeline(AppData *app, PipeLineType type);
115 static void openPlayPipeline( AppData *data );
116 static gboolean destroyPipeline(AppData *data, PipeLineType type);
117 static gboolean destroyPipelines(AppData *data);
118 static void cbItemGroupChanged(gpointer data);
119 static gboolean cbUpdateRecLength(AppData *data);
120 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data);
121 static gboolean openURI(gpointer user_data);
122 static gboolean closeFile(AppData *data);
123 static const gchar *getFileName(AppData *data);
124 static gdouble guessMediaLength(AppData *data);
125 static GstCaps *createCapsFilter(AudioFormat format);
127 static void new_pad_cb (GstElement *wavparse, GstPad *new_pad, gpointer data)
130 AppData* app = (AppData*) data;
132 ULOG_INFO("new pad");
134 sink = gst_element_factory_make ("dsppcmsink", "sink");
136 gst_bin_add (GST_BIN (app->playPipeline), sink);
138 if (!gst_element_link (wavparse, sink))
139 g_error ("link(wavparse, sink) failed!");
140 gst_element_sync_state_with_parent(sink);
144 static gboolean createPipeline(AppData *app, PipeLineType type)
146 GstElement *src = NULL;
147 GstElement *sink = NULL;
148 GstElement *filter = NULL;
149 GstElement *queue = NULL;
150 GstElement *pipeline = NULL;
151 GstElement *parse = NULL;
152 GstCaps *caps = NULL;
154 g_assert(NULL != app);
156 pipeline = gst_pipeline_new("pipeline");
158 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
161 /* create elements */
164 case PIPELINE_PLAY_MP3:
165 ULOG_INFO("mp3 playback - queue");
166 src = gst_element_factory_make ("gnomevfssrc", "source");
167 queue = gst_element_factory_make ("queue", "queue");
168 sink = gst_element_factory_make ("dspmp3sink", "sink");
170 g_object_set(G_OBJECT (queue),
171 "min-threshold-bytes", 131072,
173 g_object_set(G_OBJECT(src),
174 "location", app->openFileName,
180 src = gst_element_factory_make ("filesrc", "source");
181 /* we need also a filter to modify caps */
182 filter = gst_element_factory_make("capsfilter", "filter");
186 ULOG_INFO("using ilbc sink");
187 sink = gst_element_factory_make ("dspilbcsink", "sink");
193 ULOG_INFO("using pcm sink");
194 sink = gst_element_factory_make ("dsppcmsink", "sink");
198 ULOG_INFO("using wavparse & pcm sink");
199 parse = gst_element_factory_make ("wavparse", "parse");
206 g_object_set(G_OBJECT(src),
207 "location", app->openFileName,
210 caps = createCapsFilter(app->filter);
211 g_object_set(G_OBJECT(filter),
220 ULOG_INFO("using ilbc source");
221 src = gst_element_factory_make("dspilbcsrc", "source");
222 g_object_set(G_OBJECT(src),
230 ULOG_INFO("using pcm source");
231 src = gst_element_factory_make("dsppcmsrc", "source");
232 g_object_set(G_OBJECT (src),
233 "blocksize", DEFAULT_REC_BLOCKSIZE,
239 ULOG_INFO("using pcm source & wavenc");
240 src = gst_element_factory_make("dsppcmsrc", "source");
241 g_object_set(G_OBJECT (src),
242 "blocksize", DEFAULT_REC_BLOCKSIZE,
245 parse = gst_element_factory_make("wavenc", "enc");
249 ULOG_WARN("Unknown filter type!");
253 filter = gst_element_factory_make("capsfilter", "filter");
254 caps = createCapsFilter(app->filter);
255 g_object_set(G_OBJECT(filter),
259 sink = gst_element_factory_make("filesink", "sink");
261 g_object_set(G_OBJECT(sink),
262 "location", app->saveFileName,
267 ULOG_ERR("Invalid pipeline type!");
268 gst_object_unref(pipeline);
272 if (!src || !pipeline)
274 ULOG_ERR("Could not create GstElement!");
278 if (!sink && app->filter != FORMAT_WAV)
280 ULOG_ERR("Could not create GstElement!");
284 ULOG_INFO("Create pipeline");
286 /* add to pipeline and link */
297 ULOG_ERR("Could not create filter GstElement!");
300 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
302 if (!gst_element_link_many (src, filter, sink, NULL))
304 ULOG_ERR("gst_element_link failed for src, filter and sink!");
310 gst_bin_add_many(GST_BIN(pipeline), src, parse, sink, NULL);
311 if (!gst_element_link_many (src, parse, sink, NULL))
313 ULOG_ERR("gst_element_link failed for src, parse and sink!");
331 ULOG_ERR("Could not create filter GstElement!");
334 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
336 if (!gst_element_link_many (src, filter, sink, NULL))
338 ULOG_ERR("gst_element_link failed for src, filter and sink!");
345 gst_bin_add_many(GST_BIN(pipeline), src, parse, NULL);
346 if (!gst_element_link_many (src, parse, NULL))
348 ULOG_ERR("gst_element_link failed for src, parse and sink!");
351 app->playPipeline = pipeline;
352 g_signal_connect(parse, "pad_added",
353 G_CALLBACK(new_pad_cb), app);
362 case PIPELINE_PLAY_MP3:
364 gst_bin_add_many(GST_BIN(pipeline), src, queue, sink, NULL);
366 if(!gst_element_link_many(src, queue, sink, NULL))
368 ULOG_ERR("gst_element_link failed for src and sink!");
375 /* set application data */
376 if (type == PIPELINE_REC)
378 app->recPipeline = pipeline;
382 app->playPipeline = pipeline;
383 app->playPipelineType = type;
388 gst_caps_unref(caps);
395 static gboolean destroyPipelines(AppData *data)
397 gboolean ret = FALSE;
399 /* ugly hack with pipeline types, but works though */
400 ret != destroyPipeline(data, PIPELINE_REC);
401 ret != destroyPipeline(data, PIPELINE_PLAY);
405 static gboolean destroyPipeline(AppData *data, PipeLineType type)
409 GstElement *pipeline = NULL;
411 ULOG_INFO("%s() - Stopping playback/recording", G_STRFUNC);
416 pipeline = data->recPipeline;
418 data->recPipeline = NULL;
423 pipeline = data->playPipeline;
425 data->playPipeline = NULL;
430 if (!GST_IS_ELEMENT(pipeline))
433 /* this unallocates everything */
434 gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
436 /* for some reason the state does not update manually */
437 gst_element_get_state(pipeline, &state,
438 &pending, GST_CLOCK_TIME_NONE);
439 pipelineStateChanged(pipeline,
446 gst_object_unref(pipeline);
455 static void pipelineStateChanged (GstElement *element,
461 g_assert(NULL != data);
465 case GST_STATE_PLAYING:
466 if(APPSTATE_RECORDING == getAppState(data))
468 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_RECORDING);
469 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
472 ULOG_INFO("%s() - Recording", G_STRFUNC);
473 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
474 RECORDER_MSG_RECORDING);
476 gtk_widget_set_state(data->buttonRec, GTK_STATE_ACTIVE);
478 if (data->recUpdateId == 0 && gettimeofday(&data->recStartTv, NULL) == 0)
480 data->recUpdateId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, REC_UPDATE_INTERVAL, (GSourceFunc) cbUpdateRecLength, data, NULL);
485 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_PLAYING);
486 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
489 ULOG_INFO("%s() - Playing", G_STRFUNC);
490 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
491 RECORDER_MSG_PLAYING);
492 gtk_widget_set_state(data->buttonPlay, GTK_STATE_ACTIVE);
494 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PAUSE);
500 case GST_STATE_READY:
501 /* hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, "Ready..."); */
502 ULOG_INFO("%s() - Ready", G_STRFUNC);
503 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
507 case GST_STATE_PAUSED:
510 GstFormat fmt = GST_FORMAT_TIME;
511 ULOG_INFO("%s() - Paused", G_STRFUNC);
513 /* if pipeline pos == 0 => stopped, else => paused */
514 if (GST_IS_ELEMENT(data->playPipeline) && gst_element_query_position(data->playPipeline, &fmt, &pos) && pos != 0)
516 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_PAUSED);
517 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
518 RECORDER_MSG_PAUSED);
520 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
521 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
526 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
527 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
528 RECORDER_MSG_STOPPED);
529 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
530 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
532 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
537 ULOG_INFO("%s() - Null", G_STRFUNC);
538 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
539 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
541 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
542 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
543 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
548 ULOG_WARN("%s() - default case", G_STRFUNC);
554 static gboolean cbBus(GstBus *bus,
558 AppData *app = (AppData*)data;
560 switch (GST_MESSAGE_TYPE(message))
562 case GST_MESSAGE_WARNING:
567 gst_message_parse_error (message, &err, &debug);
568 ULOG_WARN("%s() - Warning: %s", G_STRFUNC, err->message);
574 case GST_MESSAGE_ERROR:
579 gst_message_parse_error (message, &err, &debug);
580 ULOG_ERR("%s() - Error: %s", G_STRFUNC, err->message);
584 /* flow through to eos */
587 case GST_MESSAGE_EOS:
589 ULOG_INFO("%s() - eos", G_STRFUNC);
591 switch(getAppState(app))
593 case APPSTATE_PLAYING:
594 /* stop playback after a short break*/
595 g_timeout_add(STOP_DELAY, (GSourceFunc)cbStopPlayback, data);
598 case APPSTATE_RECORDING:
599 gst_element_set_state(GST_ELEMENT(app->recPipeline),
601 destroyPipeline(app, PIPELINE_REC);
607 /* destroyPipelines(app); */
613 case GST_MESSAGE_STATE_CHANGED:
619 gst_message_parse_state_changed(message, &old, &new, &pending);
621 pipelineStateChanged(NULL, old, new, pending, app);
627 /* unhandled message */
628 ULOG_WARN("%s() - Unhandled message, type = %d", G_STRFUNC, message->type);
632 /* remove message from the queue */
636 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data)
642 app = (AppData *) data;
644 ULOG_DEBUG("delete_event");
648 destroyPipelines(app);
649 if (app->playPipeline)
650 gst_object_unref(GST_OBJECT(app->playPipeline));
652 if (app->recPipeline)
653 gst_object_unref(GST_OBJECT(app->recPipeline));
658 static gboolean cbCheckPosition (AppData *data)
660 GstFormat fmt = GST_FORMAT_TIME;
661 gint64 pos = 0, len = 0;
662 static gboolean lengthSet = FALSE;
664 g_assert(NULL != data);
667 if(!lengthSet && gst_element_query_duration(data->playPipeline, &fmt, &len))
672 size = GST_TIME_TO_SECS(len);
673 setLength(data, size); /* sets lengthEntry and adjustment */
678 /* calculate position */
679 if (gst_element_query_position(data->playPipeline, &fmt, &pos))
681 gdouble time = GST_TIME_TO_SECS(pos);
683 ULOG_DEBUG("pos = %lld, time = %f",
688 gtk_adjustment_set_value(
689 GTK_ADJUSTMENT(data->mainViewData.adjustment),
691 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
694 if (APPSTATE_PLAYING == getAppState(data))
702 static void cbNew(GtkWidget* widget, AppData *data)
704 g_assert(NULL != data);
706 if (!closeFile(data))
709 /* remove pipelines if existing */
710 destroyPipelines(data);
711 ULOG_DEBUG_F("cbNew");
712 /* destroy tmp file */
714 /* clear filenames */
715 g_free(data->openFileName);
716 data->openFileName = NULL;
717 g_free(data->saveFileName);
718 data->saveFileName = NULL;
719 /* data->filter = FORMAT_NONE;*/
720 data->file_format = FORMAT_NONE;
723 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
724 RECORDER_FILE_UNTITLED);
725 setLength(data, 0.0);
726 /* update the display + scale */
727 gtk_adjustment_set_value(GTK_ADJUSTMENT(data->mainViewData.adjustment),
729 gtk_widget_set_sensitive(data->buttonSave, FALSE);
730 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
733 gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
735 ULOG_DEBUG_F("cbNew end");
738 static void cbOpen(GtkWidget* widget, AppData *data)
740 GtkWidget* dialog = NULL;
741 gchar *tmpfile = NULL;
742 gchar *selected = NULL;
747 GtkFileFilter *filter;
750 ULOG_DEBUG_F("begin");
751 g_assert(NULL != data);
753 if (!closeFile(data))
758 filter = gtk_file_filter_new();
759 gtk_file_filter_add_mime_type(filter, "audio/x-mp3");
762 g_assert(GTK_IS_WINDOW(data->mainView));
764 dialog = hildon_file_chooser_dialog_new_with_properties(
765 GTK_WINDOW(data->mainView),
766 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
767 "file-system-model", NULL,
773 gtk_widget_show_all(dialog);
775 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
777 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
780 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
782 if (dialog != NULL && GTK_IS_WIDGET(dialog))
784 gtk_widget_destroy(dialog);
786 ULOG_DEBUG("%s() - dialog destroyed", G_STRFUNC);
790 if (NULL == selected) /* no file selected */
793 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
795 if (openFile(selected, &format, &tmpfile))
797 ULOG_INFO("%s() - openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
801 /* update filenames */
802 basename = g_path_get_basename(selected);
804 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
805 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
808 g_free(data->openFileName);
809 data->openFileName = tmpfile;
810 data->file_format = format;
811 data->filter = format;
812 g_free(data->saveFileName);
813 data->saveFileName = NULL;
814 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
816 len = guessMediaLength(data);
818 setLength(data, len);
820 setLength(data, 0.0);
822 setFormatString(data, data->file_format);
827 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
828 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
837 openURI(gpointer user_data)
841 gchar *selected = NULL;
843 gchar *tmpfile = NULL;
844 gchar *basename = NULL;
848 data = (AppData *) user_data;
850 if (NULL == data->mimeURI)
853 uri = gnome_vfs_uri_new(data->mimeURI);
854 selected = g_strdup(gnome_vfs_uri_get_path(uri));
856 gnome_vfs_uri_unref(uri);
859 g_free(data->mimeURI);
860 data->mimeURI = NULL;
862 /* TODO: the following is duplicated in cbOpen(), move to a tryOpen() function ? */
864 if (NULL == selected)
867 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
869 if (openFile(selected, &format, &tmpfile))
871 ULOG_INFO("%s: openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
875 /* update filenames */
876 basename = g_path_get_basename(selected);
878 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
879 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
882 g_free(data->openFileName);
883 data->openFileName = tmpfile;
884 data->file_format = format;
885 data->filter = format;
886 g_free(data->saveFileName);
887 data->saveFileName = NULL;
888 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
890 len = guessMediaLength(data);
892 setLength(data, len);
894 setLength(data, 0.0);
896 setFormatString(data, data->file_format);
901 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
902 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
910 static void openPlayPipeline( AppData *data )
913 GstFormat fmt = GST_FORMAT_TIME;
916 /* create pipelines */
917 /* check file type */
918 switch (data->file_format)
925 destroyPipelines(data);
926 data->filter = data->file_format;
927 createPipeline(data, PIPELINE_PLAY);
931 destroyPipelines(data);
932 data->filter = data->file_format;
933 createPipeline(data, PIPELINE_PLAY_MP3);
938 ULOG_WARN("%s() - unknown file_format", G_STRFUNC);
939 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Unknown filetype!"));
944 if (!GST_IS_ELEMENT(data->playPipeline))
946 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline!"));
950 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_READY);
951 gst_element_get_state(GST_ELEMENT(data->playPipeline), NULL, NULL, GST_CLOCK_TIME_NONE /* or ns */);
953 /* calculate length */
954 if (gst_element_query_duration (data->playPipeline, &fmt, &len))
958 size = GST_TIME_TO_SECS(len);
959 ULOG_INFO("playSize: len:%lld size:%f", len, size);
960 setLength(data, size);
966 ULOG_INFO("playSize else");
967 setLength(data, 0.0);
972 /* returns whether the action can proceed or should be aborted */
974 closeFile(AppData *data)
982 note = hildon_note_new_confirmation_add_buttons(GTK_WINDOW(data->mainView), _("Save recording?"),
983 _("Yes"), GTK_RESPONSE_YES,
984 _("No"), GTK_RESPONSE_NO,
985 _("Cancel"), GTK_RESPONSE_CANCEL,
988 i = gtk_dialog_run(GTK_DIALOG(note));
989 gtk_widget_destroy(note);
993 case GTK_RESPONSE_CANCEL:
996 case GTK_RESPONSE_NO:
999 case GTK_RESPONSE_YES:
1001 cbSaveAs(NULL, data);
1005 ULOG_WARN("%s(): unknown response from dialog: %d", G_STRFUNC, i);
1010 static const gchar *
1011 getFileName(AppData *data)
1014 return gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1019 static void cbSave(GtkWidget* widget, AppData *data)
1021 GtkWidget* dialog = NULL;
1022 const gchar *current;
1023 gchar *selected = NULL;
1027 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1029 current = gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
1030 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1032 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1036 /* if saveFileName does not exist run saveas */
1037 if (NULL == data->saveFileName)
1040 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1041 GTK_WINDOW(data->mainView),
1042 GTK_FILE_CHOOSER_ACTION_SAVE));
1045 gtk_widget_show_all(dialog);
1047 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1049 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1052 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1054 gtk_widget_destroy(dialog);
1056 if (NULL != selected)
1058 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC,
1060 g_free(data->saveFileName);
1061 data->saveFileName = g_strdup_printf("%s%s", selected, getExtension(data->file_format));
1072 if (doSave(gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry)), data->saveFileName, data->file_format))
1074 gchar *basename = g_path_get_basename(data->saveFileName);
1075 ULOG_INFO("%s() - file succesfully saved!", G_STRFUNC);
1076 g_free(data->openFileName);
1077 data->openFileName = g_strdup(data->saveFileName);
1079 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1080 data->saveFileName);
1081 gtk_widget_set_sensitive(data->buttonSave, FALSE);
1082 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
1086 ULOG_DEBUG("%s() - end", G_STRFUNC);
1090 static void cbSettings(GtkWidget* widget, AppData *data)
1092 settings_edit( widget, data );
1095 static void cbEmailing(GtkWidget* widget, AppData *data)
1098 GSList *list = NULL;
1100 g_assert(NULL != data);
1102 if (g_file_test(getFileName(data), G_FILE_TEST_EXISTS))
1104 file = file2uri(getFileName(data));
1105 ULOG_INFO("Emailing: %s", file);
1106 list = g_slist_append(list, file);
1107 if (osso_email_files_email(data->osso, list) != OSSO_OK)
1108 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Emailing failed"));
1115 static void cbSaveAs(GtkWidget* widget, AppData *data)
1117 GtkWidget* dialog = NULL;
1118 const gchar *current;
1119 gchar *selected = NULL;
1121 g_assert(NULL != data);
1123 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1125 current = getFileName(data);
1126 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1128 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1133 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1134 GTK_WINDOW(data->mainView),
1135 GTK_FILE_CHOOSER_ACTION_SAVE));
1137 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog),
1138 get_default_dir() );
1141 gtk_widget_show_all(dialog);
1143 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1145 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1148 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1149 gtk_widget_destroy(dialog);
1151 if (NULL == selected)
1154 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
1156 g_free(data->saveFileName);
1157 data->saveFileName = NULL;
1159 if (saveFile(selected, data->openFileName, data->file_format, &(data->saveFileName)))
1164 g_assert(data->saveFileName);
1166 /* set new title that has the file name */
1167 basename = g_path_get_basename(data->saveFileName);
1168 ULOG_DEBUG("%s() - file '%s' succesfully saved!", G_STRFUNC, data->saveFileName);
1170 gtk_window_set_title(GTK_WINDOW(data->mainView), basename);
1172 /* Houston, we have a kludge:
1173 * for AU files we need to keep the old tmpfile for playback
1174 * for RAW/iLBC files, we can remove the tmpfile and point openFileName to the saved file
1176 ext = getExtension(data->file_format);
1177 if (strcmp(ext, EXTENSION_AU) != 0)
1179 g_free(data->openFileName);
1180 data->openFileName = g_strdup(data->saveFileName);
1183 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1184 data->saveFileName);
1191 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Saving file failed!"));
1197 ULOG_DEBUG("%s() - end", G_STRFUNC);
1200 static void cbRec(GtkWidget* widget, AppData *data)
1202 g_assert(NULL != data);
1204 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1206 if (APPSTATE_READY != getAppState(data))
1208 ULOG_WARN("%s() - state different than READY -> return", G_STRFUNC);
1212 if (!closeFile(data))
1215 /* clear filenames, use tmp file */
1216 g_free(data->openFileName);
1217 data->openFileName = NULL;
1219 g_free(data->saveFileName);
1220 data->saveFileName = NULL;
1222 switch (data->filter)
1225 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1226 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1230 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1231 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1235 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1236 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1240 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1241 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1246 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1247 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1251 ULOG_INFO("%s() - creating pipelines", G_STRFUNC);
1252 /* start recording */
1253 /* create related pipelines */
1254 if (createPipeline(data, PIPELINE_REC))
1256 ULOG_INFO("%s() - starting recording", G_STRFUNC);
1257 /* start recording */
1258 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1261 /* update display */
1262 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1263 data->saveFileName);
1265 setAppState(data, APPSTATE_RECORDING);
1266 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1267 gtk_window_set_title(GTK_WINDOW(data->mainView), RECORDER_FILE_UNTITLED);
1268 data->file_format = data->filter;
1269 setFormatString(data, data->file_format);
1273 ULOG_ERR("Could not create rec pipeline!");
1274 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline"));
1275 setAppState(data, APPSTATE_READY);
1278 ULOG_DEBUG("%s() - end", G_STRFUNC);
1281 static void cbPlay(GtkWidget* widget, AppData *data)
1283 const gchar * file = NULL;
1285 g_assert(NULL != data);
1287 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1289 file = getFileName(data);
1290 if (NULL == data->openFileName || NULL == file || strcmp(file, RECORDER_FILE_UNTITLED) == 0)
1292 ULOG_WARN("%s() - nothing to play", G_STRFUNC);
1296 openPlayPipeline(data);
1298 if (APPSTATE_PLAYING == getAppState(data))
1300 if (GST_IS_ELEMENT(data->playPipeline))
1302 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_PAUSED);
1303 setAppState(data, APPSTATE_READY);
1308 if (APPSTATE_READY != getAppState(data))
1310 ULOG_WARN("%s() - state different than PLAYING or READY -> return", G_STRFUNC);
1314 ULOG_INFO("filename %s", file);
1316 /*openPlayPipeline( data );*/
1318 /*if ( ! GST_IS_ELEMENT(data->playPipeline) )
1320 if (g_strrstr(data->openFileName, EXTENSION_RAW))
1322 ULOG_INFO("cbOpen() - file was raw, assuming audio/x-raw-int, 8kHz, 1 ch, 16-bit");
1323 destroyPipelines(data);
1324 createPipeline(data, PIPELINE_PLAY);
1328 if (! GST_IS_ELEMENT(data->playPipeline))
1330 ULOG_WARN("%s() - playPipeline does not exist", G_STRFUNC);
1334 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1337 setAppState(data, APPSTATE_PLAYING);
1339 g_timeout_add(PLAY_UPDATE_INTERVAL, (GSourceFunc)cbCheckPosition, data);
1341 ULOG_DEBUG("%s() - end", G_STRFUNC);
1344 static void cbStop(GtkWidget* widget, AppData *data)
1346 g_assert(NULL != data);
1348 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1350 /* check if we are playing/recording */
1353 if (APPSTATE_PLAYING != getAppState(data) &&
1354 APPSTATE_RECORDING != getAppState(data))
1356 ULOG_WARN("cbStop() - state different than PLAYING or RECORDING "
1362 /* stop playing or recording */
1363 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
1364 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1365 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
1367 /* destroy related pipeline */
1368 switch(getAppState(data))
1370 case APPSTATE_PLAYING:
1371 /* don't destroy the playing pipeline. Instead, set the pipeline to PAUSED */
1372 /* destroyPipeline(data, PIPELINE_PLAY); */
1373 ULOG_INFO("%s() - Setting playPipeline state to PAUSED", G_STRFUNC);
1374 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1377 case APPSTATE_READY:
1378 /* seek to zero, but not for PCM pipeline */
1379 /* if (data->playPipelineType == PIPELINE_PLAY || seekToZero(data, GST_ELEMENT(data->playPipeline))) */
1380 if ( !GST_IS_ELEMENT(data->playPipeline) || seekToZero(data, GST_ELEMENT(data->playPipeline)))
1382 gtk_adjustment_set_value(
1383 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1384 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1385 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
1386 RECORDER_MSG_STOPPED);
1390 case APPSTATE_RECORDING:
1393 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1395 destroyPipeline(data, PIPELINE_REC);
1396 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1397 data->saved = FALSE;
1399 len = guessMediaLength(data);
1401 setLength(data, len);
1407 /* seekToZero(data, GST_ELEMENT(data->playPipeline)); */
1408 /* should not come here */
1412 setAppState(data, APPSTATE_READY);
1414 ULOG_DEBUG("%s() - end", G_STRFUNC);
1418 /* ui construction functions */
1420 static GtkWidget* createToolBar(AppData *data)
1422 GtkToolbar* toolBar = NULL;
1424 GtkToolItem* new = NULL;
1425 GtkToolItem* open = NULL;
1426 GtkToolItem* save = NULL;
1427 GtkToolItem* saveas = NULL;
1428 GtkToolItem* sep = NULL;
1429 GtkToolItem* play = NULL;
1430 GtkToolItem* rec = NULL;
1431 GtkToolItem* stop = NULL;
1433 /* create buttons */
1434 new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
1435 open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
1436 save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
1437 data->buttonSave = GTK_WIDGET(save);
1438 saveas = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE_AS);
1439 data->buttonSaveAs = GTK_WIDGET(saveas);
1440 gtk_widget_set_sensitive(data->buttonSave, FALSE);
1441 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
1444 gtk_tool_item_set_expand( GTK_TOOL_ITEM(new), TRUE );
1445 gtk_tool_item_set_expand( GTK_TOOL_ITEM(open), TRUE );
1446 gtk_tool_item_set_expand( GTK_TOOL_ITEM(saveas), TRUE );
1448 rec = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_RECORD);
1449 data->buttonRec = GTK_WIDGET(rec);
1450 play = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
1451 data->buttonPlay = GTK_WIDGET(play);
1452 stop = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
1454 gtk_tool_item_set_expand( GTK_TOOL_ITEM(rec), TRUE );
1455 gtk_tool_item_set_expand( GTK_TOOL_ITEM(play), TRUE );
1456 gtk_tool_item_set_expand( GTK_TOOL_ITEM(stop), TRUE );
1458 /* create separator */
1459 sep = gtk_separator_tool_item_new();
1461 /* create the toolbar itself */
1462 toolBar = GTK_TOOLBAR(gtk_toolbar_new());
1464 /* add items to toolbar */
1465 gtk_toolbar_insert(toolBar, new, -1);
1466 gtk_toolbar_insert(toolBar, open, -1);
1468 gtk_toolbar_insert(toolBar, save, -1);
1470 gtk_toolbar_insert(toolBar, saveas, -1);
1471 gtk_toolbar_insert(toolBar, sep, -1);
1472 gtk_toolbar_insert(toolBar, rec, -1);
1473 gtk_toolbar_insert(toolBar, play, -1);
1474 gtk_toolbar_insert(toolBar, stop, -1);
1476 /* connect signals */
1477 g_signal_connect(G_OBJECT(new), "clicked",
1480 g_signal_connect(G_OBJECT(open), "clicked",
1484 g_signal_connect(G_OBJECT(save), "clicked",
1488 g_signal_connect(G_OBJECT(saveas), "clicked",
1489 G_CALLBACK(cbSaveAs),
1491 g_signal_connect(G_OBJECT(rec), "clicked",
1494 g_signal_connect(G_OBJECT(play), "clicked",
1497 g_signal_connect(G_OBJECT(stop), "clicked",
1501 return GTK_WIDGET(toolBar);
1505 static void cbItemGroupChanged( gpointer data )
1507 AppData* app = (AppData* ) data;
1508 GValue active ={G_TYPE_INVALID};
1511 g_value_init(&active, G_TYPE_INT);
1513 g_object_get_property(G_OBJECT(app->radio_pcma), "active", &active);
1514 pcma = g_value_get_int(&active);
1515 g_object_get_property(G_OBJECT(app->radio_ilbc), "active", &active);
1516 ilbc = g_value_get_int(&active);
1517 g_object_get_property(G_OBJECT(app->radio_pcm), "active", &active);
1518 pcm = g_value_get_int(&active);
1520 ULOG_INFO("change type pcma=%d ilbc=%d pcm=%d",pcma, ilbc, pcm);
1522 app->filter = FORMAT_PCMA;
1523 else if ( ilbc == 1 )
1524 app->filter = FORMAT_ILBC;
1525 else if ( pcm == 1 )
1526 app->filter = FORMAT_WAV;
1530 ULOG_INFO("filter type=%d", app->filter);
1533 static void cbItemClose(GtkWidget *widget, gpointer data)
1537 if (!closeFile(data))
1543 /* Create the menu items needed for the main view */
1544 static void createMenu( AppData *data )
1546 /* Create needed variables */
1547 GSList *group = NULL;
1549 GtkWidget *menu_file;
1550 GtkWidget *menu_others;
1551 GtkWidget *item_file;
1552 GtkWidget *item_file_open;
1553 GtkWidget *item_file_save_as;
1554 GtkWidget *item_others;
1555 GtkWidget *item_pcma;
1556 GtkWidget *item_pcmu;
1557 GtkWidget *item_ilbc;
1558 GtkWidget *item_pcm;
1559 GtkWidget *item_settings;
1560 GtkWidget *item_email;
1562 GtkWidget *item_radio_type1;
1564 GtkWidget *item_close;
1565 GtkWidget *item_separator;
1567 /* Get the menu from view */
1568 main_menu = GTK_MENU(gtk_menu_new());
1569 hildon_window_set_menu(data->mainView, main_menu);
1571 /* Create new submenu for "Others" */
1572 menu_file = gtk_menu_new ();
1573 menu_others = gtk_menu_new ();
1575 /* Create menu items */
1576 item_file = gtk_menu_item_new_with_label (_("File"));
1577 item_file_open = gtk_menu_item_new_with_label(_("Open..."));
1578 item_file_save_as = gtk_menu_item_new_with_label(_("Save as..."));
1579 item_others = gtk_menu_item_new_with_label (_("Recording format"));
1580 item_settings = gtk_menu_item_new_with_label (_("Settings"));
1581 item_email = gtk_menu_item_new_with_label(_("Send via e-mail..."));
1583 item_pcma = gtk_radio_menu_item_new_with_label(
1584 group, FORMAT_NAME_PCMA);
1585 item_ilbc = gtk_radio_menu_item_new_with_label_from_widget(
1586 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_ILBC);
1587 item_pcmu = gtk_radio_menu_item_new_with_label_from_widget(
1588 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_PCMU);
1589 item_pcm = gtk_radio_menu_item_new_with_label_from_widget(
1590 GTK_RADIO_MENU_ITEM(item_pcma), FORMAT_NAME_WAV);
1592 data->filter = get_default_filter();
1594 if (data->filter == FORMAT_ILBC)
1595 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_ilbc), TRUE);
1596 else if (data->filter == FORMAT_WAV)
1597 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_pcm), TRUE);
1598 else if (data->filter == FORMAT_PCMA)
1599 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_pcma), TRUE);
1602 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_ilbc), TRUE);
1603 data->filter = FORMAT_ILBC;
1606 data->radio_pcma = item_pcma;
1607 data->radio_ilbc = item_ilbc;
1608 data->radio_pcm = item_pcm;
1610 data->radiotype = item_radio_type1;
1612 item_close = gtk_menu_item_new_with_label(_("Close"));
1613 item_separator = gtk_separator_menu_item_new();
1615 /* Add menu items to right menus */
1616 gtk_menu_append(main_menu, item_file );
1617 gtk_menu_append(menu_file, item_file_open );
1618 gtk_menu_append(menu_file, item_file_save_as );
1619 gtk_menu_append(menu_file, item_email );
1620 gtk_menu_append(main_menu, item_others );
1621 gtk_menu_append(menu_others, item_pcm );
1622 gtk_menu_append(menu_others, item_pcma );
1623 gtk_menu_append(menu_others, item_ilbc);
1625 gtk_menu_append(main_menu, item_settings );
1627 gtk_menu_append(main_menu, item_close );
1629 /* Add others submenu to the "Others" item */
1630 gtk_menu_item_set_submenu(
1631 GTK_MENU_ITEM(item_file), menu_file );
1632 gtk_menu_item_set_submenu(
1633 GTK_MENU_ITEM(item_others), menu_others );
1635 /* Attach the callback functions to the activate signal */
1636 g_signal_connect( G_OBJECT( item_file_open), "activate",
1637 GTK_SIGNAL_FUNC (cbOpen), data);
1638 g_signal_connect( G_OBJECT( item_file_save_as), "activate",
1639 GTK_SIGNAL_FUNC (cbSaveAs), data);
1640 g_signal_connect( G_OBJECT( item_settings ), "activate",
1641 GTK_SIGNAL_FUNC (cbSettings), data);
1642 g_signal_connect( G_OBJECT( item_email ), "activate",
1643 GTK_SIGNAL_FUNC (cbEmailing), data);
1644 g_signal_connect( G_OBJECT( item_close ), "activate",
1645 GTK_SIGNAL_FUNC (cbItemClose), data);
1647 g_signal_connect_swapped(G_OBJECT(item_pcma), "activate", G_CALLBACK(cbItemGroupChanged), data);
1648 g_signal_connect_swapped(G_OBJECT(item_pcm), "activate", G_CALLBACK(cbItemGroupChanged), data);
1650 /* Make all menu widgets visible */
1652 gtk_widget_show_all( GTK_WIDGET( main_menu ) );
1656 evKeypress(GtkWidget *widget, GdkEventKey *ev, AppData *appdata)
1662 cbRec(widget, appdata);
1665 cbPlay(widget, appdata);
1668 cbStop(widget, appdata);
1678 gboolean maemo_recorder_ui_new(AppData *data)
1680 HildonProgram *app = NULL;
1681 HildonWindow *window = NULL;
1682 GtkWidget *hbox = NULL;
1683 GtkWidget *vbox = NULL;
1684 GtkWidget *label = NULL;
1685 GtkWidget *entry1 = NULL;
1686 GtkWidget *entry2 = NULL;
1687 GtkWidget *entry3 = NULL;
1688 GtkWidget *toolBar = NULL;
1689 GtkWidget *infohbox = NULL;
1690 GtkWidget *table = NULL;
1691 GtkWidget *scale = NULL;
1692 GtkObject *adjustment = NULL;
1694 g_assert(NULL != data);
1696 app = HILDON_PROGRAM(hildon_program_get_instance());
1697 g_set_application_name(RECORDER_APP_TITLE);
1700 window = HILDON_WINDOW(hildon_window_new());
1702 hildon_program_add_window(app, window);
1704 /* content for main view */
1706 /* create vbox, divides control area and view area */
1707 vbox = gtk_vbox_new(FALSE, 0);
1709 /* create hbox to divide control area */
1710 hbox = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
1712 /* create toolbar */
1713 toolBar = createToolBar(data);
1715 /* create table for labels */
1716 table = gtk_table_new (4, 2, FALSE);
1717 gtk_table_set_homogeneous(GTK_TABLE(table), FALSE);
1719 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
1720 gtk_table_set_col_spacings (GTK_TABLE (table), HILDON_MARGIN_TRIPLE);
1722 label = gtk_label_new_with_mnemonic(_("Filename:"));
1723 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1724 gtk_table_attach_defaults (GTK_TABLE (table),
1728 entry1 = gtk_entry_new();
1729 gtk_entry_set_has_frame(GTK_ENTRY(entry1), FALSE);
1730 gtk_entry_set_text(GTK_ENTRY (entry1), _(RECORDER_FILE_UNTITLED));
1731 gtk_entry_set_editable(GTK_ENTRY(entry1), FALSE);
1732 gtk_table_attach_defaults(GTK_TABLE (table), entry1, 1, 2, 0, 1);
1733 gtk_label_set_mnemonic_widget(GTK_LABEL (label), entry1);
1735 label = gtk_label_new_with_mnemonic (_("Length:"));
1736 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1737 gtk_table_attach_defaults (GTK_TABLE (table),
1741 entry2 = gtk_entry_new ();
1742 gtk_entry_set_has_frame(GTK_ENTRY(entry2), FALSE);
1743 gtk_entry_set_text (GTK_ENTRY (entry2), "0:00.00");
1744 gtk_entry_set_editable(GTK_ENTRY(entry2), FALSE);
1745 gtk_table_attach_defaults (GTK_TABLE (table), entry2, 1, 2, 1, 2);
1746 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry2);
1748 /* audio format field */
1749 label = gtk_label_new_with_mnemonic(_("Format:"));
1750 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1751 gtk_table_attach_defaults (GTK_TABLE (table),
1755 entry3 = gtk_entry_new();
1756 gtk_entry_set_has_frame(GTK_ENTRY(entry3), FALSE);
1757 gtk_entry_set_width_chars(GTK_ENTRY(entry3), 40);
1758 gtk_entry_set_text (GTK_ENTRY (entry3), RECORDER_FMT_STRING_NONE);
1759 gtk_entry_set_editable(GTK_ENTRY(entry3), FALSE);
1760 data->mainViewData.formatEntry = GTK_WIDGET(entry3);
1762 gtk_table_attach_defaults (GTK_TABLE (table), entry3, 1, 2, 2, 3);
1763 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry3);
1765 label = gtk_label_new_with_mnemonic(_("State:"));
1766 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1767 gtk_table_attach_defaults (GTK_TABLE (table),
1771 entry3 = gtk_entry_new ();
1772 gtk_entry_set_has_frame(GTK_ENTRY(entry3), FALSE);
1773 gtk_entry_set_text (GTK_ENTRY (entry3), RECORDER_MSG_READY);
1774 gtk_entry_set_editable(GTK_ENTRY(entry3), FALSE);
1775 gtk_table_attach_defaults (GTK_TABLE (table), entry3, 1, 2, 3, 4);
1776 gtk_label_set_mnemonic_widget(GTK_LABEL (label), entry3);
1778 adjustment = gtk_adjustment_new (0.00,
1785 scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1787 /* gtk_table_attach_defaults (GTK_TABLE (table),
1791 /* connect signals */
1792 g_signal_connect(G_OBJECT(adjustment), "value-changed", G_CALLBACK(cbUserSeek), data);
1793 g_signal_connect(G_OBJECT(scale), "format-value", G_CALLBACK(cbFormatSeekbarValue), data);
1794 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(cbDestroy), data);
1795 g_signal_connect(G_OBJECT(window), "key-press-event",
1796 G_CALLBACK(evKeypress), data);
1798 /* packing the view */
1799 gtk_container_add (GTK_CONTAINER(window), vbox);
1800 infohbox = gtk_hbox_new(FALSE, 0);
1801 gtk_box_pack_start (GTK_BOX(infohbox), table, FALSE, TRUE, 0);
1802 gtk_box_pack_start (GTK_BOX(vbox), infohbox, FALSE, TRUE, 0);
1803 gtk_box_pack_start (GTK_BOX(vbox), scale, FALSE, FALSE, 0);
1804 /* gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 0); */
1806 hildon_window_add_toolbar(window, GTK_TOOLBAR(toolBar));
1808 /* store needed widgets */
1810 data->mainView = window;
1811 data->mainViewData.toolBar = GTK_WIDGET(toolBar);
1812 data->mainViewData.fileNameEntry = GTK_WIDGET(entry1);
1813 data->mainViewData.lengthEntry = GTK_WIDGET(entry2);
1814 data->mainViewData.stateEntry = GTK_WIDGET(entry3);
1815 data->mainViewData.adjustment = GTK_OBJECT(adjustment);
1818 gtk_widget_show_all(GTK_WIDGET(window));
1826 maemo_recorder_mime_open(gpointer user_data, gint argc, gchar **argv)
1830 ULOG_DEBUG("%s with %d arguments", __FUNCTION__, argc);
1835 g_assert(user_data);
1836 data = (AppData *) user_data;
1838 if (argv[0] != NULL)
1840 ULOG_DEBUG("request to open %s", argv[0]);
1841 g_free(data->mimeURI);
1842 data->mimeURI = g_strdup(argv[0]);
1843 g_idle_add(openURI, (gpointer) data);
1844 gtk_window_present(GTK_WINDOW(data->mainView));
1848 static void seekToTime(GstElement *pipeline, gdouble secs)
1850 g_assert(NULL != pipeline);
1851 ULOG_DEBUG("Seeking to: %.2f", secs);
1853 /* time must be nanoseconds */
1854 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1855 GST_SEEK_TYPE_SET, (gint64) (secs * GST_SECOND),
1856 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1858 ULOG_WARN("seekToTime failed!");
1861 ULOG_DEBUG("seekToTime succeeded");
1864 static gboolean seekToZero(AppData *data, GstElement *pipeline)
1867 g_assert(NULL != pipeline);
1868 ULOG_DEBUG("Seeking to zero");
1870 /* time must be nanoseconds */
1871 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1872 GST_SEEK_TYPE_SET, (gint64) 0,
1873 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1875 ULOG_ERR("seekToZero failed! Trying to destroy and re-create pipeline");
1876 plType = data->playPipelineType;
1878 /* gst_element_set_state(pipeline, GST_STATE_READY); */
1879 destroyPipeline(data, plType);
1880 return createPipeline(data, plType);
1883 ULOG_DEBUG("seekToZero succeeded");
1888 setFormatString(AppData *data, AudioFormat afmt)
1893 /* these are pretty much always the same */
1895 gint rate = DEFAULT_RATE; /* 8000 */
1899 g_assert(GTK_IS_ENTRY(data->mainViewData.formatEntry));
1904 format = FORMAT_NAME_PCMA;
1907 format = FORMAT_NAME_PCMU;
1910 format = FORMAT_NAME_ILBC;
1913 /* TODO: we can play wavs with many sampling rates, 2 channels */
1914 /* we really should migrate to the better format spec */
1916 format = FORMAT_NAME_WAV;
1920 format = FORMAT_NAME_PCM;
1924 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.formatEntry), RECORDER_FMT_STRING_NONE);
1928 str = g_strdup_printf("%s, %d %s, %d Hz, %d %s", format, channels, _("ch"), rate, bits, _("bits"));
1929 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.formatEntry), str);
1933 static void setLength(AppData *data, gdouble secs)
1943 g_object_set(G_OBJECT(data->mainViewData.adjustment),
1946 gtk_adjustment_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1952 secs -= mins * 60.0;
1955 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
1958 ULOG_INFO("Setting length to %s", tmp);
1960 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
1965 static gdouble guessMediaLength(AppData *data)
1967 GnomeVFSFileSize size = 0;
1968 gdouble bitrate = 0.0;
1971 if (data->openFileName)
1972 size = getFileLength(data->openFileName);
1979 ULOG_DEBUG("file size: %llu bytes", size);
1981 switch (data->file_format)
1984 bitrate = ILBC_BITRATE_20;
1989 bitrate = PCMA_BITRATE;
1999 len = (((gdouble) size) * 8.0) / (bitrate);
2000 ULOG_DEBUG("guessed media length: %.2f secs", len);
2005 static GstCaps *createCapsFilter(AudioFormat format)
2010 return gst_caps_new_simple(
2012 "rate", G_TYPE_INT, ILBC_RATE,
2013 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
2014 "mode", G_TYPE_INT, 20, /* 20 ms frames */
2017 return gst_caps_new_simple(
2019 "rate", G_TYPE_INT, DEFAULT_RATE,
2020 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
2023 return gst_caps_new_simple(
2025 "rate", G_TYPE_INT, DEFAULT_RATE,
2026 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
2030 return gst_caps_new_simple(
2032 "rate", G_TYPE_INT, PCM_RATE,
2033 "signed", G_TYPE_BOOLEAN, TRUE,
2034 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
2035 "endianness", G_TYPE_INT, PCM_ENDIANNESS,
2036 "width", G_TYPE_INT, PCM_WIDTH,
2037 "depth", G_TYPE_INT, PCM_DEPTH,
2040 ULOG_WARN("%s(): creating ANY caps", G_STRFUNC);
2041 return gst_caps_new_any();
2045 static gboolean cbStopPlayback(AppData *data)
2048 ULOG_INFO("Stopping playback");
2050 g_assert(data != NULL);
2052 ret = gst_element_set_state(GST_ELEMENT(data->playPipeline),
2054 if (seekToZero(data, GST_ELEMENT(data->playPipeline)))
2056 gtk_adjustment_set_value(
2057 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
2058 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
2060 setAppState(data, APPSTATE_READY);
2061 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
2062 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
2067 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data)
2069 /*ULOG_INFO("cbUserSeek");*/
2072 g_return_if_fail(data != NULL);
2073 app = (AppData *) data;
2075 if (getAppState(app) != APPSTATE_READY || NULL == app->playPipeline)
2078 seekToTime(app->playPipeline, gtk_adjustment_get_value(adjustment));
2081 static gchar *cbFormatSeekbarValue(GtkScale *scale, gdouble value)
2083 /* ULOG_INFO("cbFormatSeekbarValue");*/
2085 gint digits = gtk_scale_get_digits(scale);
2090 value -= mins * 60.0;
2091 return g_strdup_printf("%d:%0*.*f", mins, digits + 3, digits, value);
2094 return g_strdup_printf("%0.*f", digits, value);
2097 static gboolean cbUpdateRecLength(AppData *data)
2104 if (gettimeofday(&tv, NULL) != 0)
2107 secs = tv.tv_sec - data->recStartTv.tv_sec;
2108 secs += ((tv.tv_usec - data->recStartTv.tv_usec) / 1000000.0);
2113 secs -= mins * 60.0;
2114 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
2117 tmp = g_strdup_printf("%0.2f", secs);
2119 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
2123 if (getAppState(data) == APPSTATE_RECORDING)
2126 data->recUpdateId = 0;