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/hildon-program.h>
28 #include <hildon/hildon-note.h>
29 #include <hildon/hildon-banner.h>
30 #include <hildon/hildon-defines.h>
31 #include <hildon/hildon-file-system-model.h>
32 #include <hildon/hildon-file-chooser-dialog.h>
35 #include <libmodest-dbus-client/libmodest-dbus-client.h>
36 #include "maemo-recorder.h"
37 #include "maemo-recorder-ui.h"
38 #include "maemo-recorder-file.h"
41 #define DEFAULT_REC_BLOCKSIZE "160"
43 #define STOP_DELAY 500
44 #define REC_UPDATE_INTERVAL 750
45 #define PLAY_UPDATE_INTERVAL 200
49 #define GST_TIME_MINS(t) \
50 (guint) ((((GstClockTime)(t)) / (GST_SECOND * 60)) % 60)
51 #define GST_TIME_SECS(t) \
52 (guint) ((((GstClockTime)(t)) / GST_SECOND) % 60)
53 #define GST_TIME_TO_SECS(t) \
54 (gdouble) (((gdouble)(t)) / (gdouble) GST_SECOND) /* GST_SECOND should be 1e9 */
55 #define GST_TIME_MSECS(t) \
56 (guint) (((GstClockTime)(t)) % GST_SECOND)
58 #define RECORDER_APP_TITLE "Maemo Recorder"
59 #define RECORDER_MSG_READY _("Ready")
60 #define RECORDER_MSG_STOPPED _("Stopped")
61 #define RECORDER_MSG_PAUSED _("Paused")
62 #define RECORDER_MSG_PLAYING _("Playing")
63 #define RECORDER_MSG_RECORDING _("Recording")
64 #define RECORDER_FILE_UNTITLED _("Untitled")
66 #define RECORDER_FMT_STRING_NONE _("N/A")
68 /* general enumerations */
83 /* function prototypes */
85 static gboolean cbBus (GstBus *bus,
89 static void pipelineStateChanged (GstElement *element,
95 static void seekToTime(GstElement *pipeline, gdouble secs);
96 static gboolean seekToZero(AppData *data, GstElement *pipeline);
97 static void setLength(AppData *data, gdouble secs);
98 static void setFormatString(AppData *data, AudioFormat afmt);
99 static gboolean cbStopPlayback(AppData *data);
100 static void cbStop(GtkWidget* widget, AppData *data);
101 static void cbPlay(GtkWidget* widget, AppData *data);
102 static void cbRec(GtkWidget* widget, AppData *data);
103 static void cbNew(GtkWidget* widget, AppData *data);
104 static void cbOpen(GtkWidget* widget, AppData *data);
105 /*static void cbSave(GtkWidget* widget, AppData *data);*/
106 static void cbSaveAs(GtkWidget* widget, AppData *data);
107 static void cbItemClose(GtkWidget *widget, gpointer data);
108 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data);
109 static gchar* cbFormatSeekbarValue(GtkScale *scale, gdouble value);
110 static GtkWidget* createToolBar(AppData *data);
111 static void createMenu( AppData *data );
112 static gboolean createPipeline(AppData *app, PipeLineType type);
113 static void openPlayPipeline( AppData *data );
114 static gboolean destroyPipeline(AppData *data, PipeLineType type);
115 static gboolean destroyPipelines(AppData *data);
116 static void cbItemGroupChanged(gpointer data);
117 static gboolean cbUpdateRecLength(AppData *data);
118 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data);
119 static gboolean openURI(gpointer user_data);
120 static gboolean closeFile(AppData *data);
121 static const gchar *getFileName(AppData *data);
122 static gdouble guessMediaLength(AppData *data);
123 static GstCaps *createCapsFilter(AudioFormat format);
125 static gboolean lengthSet = FALSE;
127 static gboolean createPipeline(AppData *app, PipeLineType type)
129 GstElement *src = NULL;
130 GstElement *sink = NULL;
131 GstElement *filter = NULL;
132 GstElement *queue = NULL;
133 GstElement *pipeline = NULL;
134 GstElement *parse = NULL;
135 GstElement *bin = NULL;
136 GstCaps *caps = NULL;
138 g_assert(NULL != app);
140 /* create elements */
143 case PIPELINE_PLAY_MP3:
144 ULOG_INFO("mp3 playback - queue");
145 bin = gst_element_factory_make ("playbin2", "bin");
146 gchar* uri = g_strdup_printf("file://%s", app->openFileName);
147 g_object_set(G_OBJECT(bin),
151 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (bin)),
154 app->playPipeline = bin;
155 app->playPipelineType = type;
161 src = gst_element_factory_make ("filesrc", "source");
162 /* we need also a filter to modify caps */
163 filter = gst_element_factory_make("capsfilter", "filter");
167 ULOG_INFO("using ilbc sink");
168 sink = gst_element_factory_make ("dspilbcsink", "sink");
174 ULOG_INFO("using pcm sink");
175 sink = gst_element_factory_make ("pulsesink", "sink");
179 ULOG_INFO("using wavparse & pcm sink");
180 bin = gst_element_factory_make ("playbin2", "bin");
181 gchar* uri = g_strdup_printf("file://%s", app->openFileName);
182 g_object_set(G_OBJECT(bin),
187 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (bin)),
190 app->playPipeline = bin;
191 app->playPipelineType = type;
200 g_object_set(G_OBJECT(src),
201 "location", app->openFileName,
204 caps = createCapsFilter(app->filter);
205 g_object_set(G_OBJECT(filter),
214 ULOG_INFO("using ilbc source");
215 src = gst_element_factory_make("dspilbcsrc", "source");
216 g_object_set(G_OBJECT(src),
225 ULOG_INFO("using pcm source");
226 src = gst_element_factory_make("pulsesrc", "source");
227 /*g_object_set(G_OBJECT (src),
228 "blocksize", DEFAULT_REC_BLOCKSIZE,
234 ULOG_INFO("using pcm source & wavenc");
235 src = gst_element_factory_make("pulsesrc", "source");
236 parse = gst_element_factory_make("wavenc", "enc");
240 ULOG_WARN("Unknown filter type!");
244 filter = gst_element_factory_make("capsfilter", "filter");
245 caps = createCapsFilter(app->filter);
246 g_object_set(G_OBJECT(filter),
250 sink = gst_element_factory_make("filesink", "sink");
252 g_object_set(G_OBJECT(sink),
253 "location", app->saveFileName,
258 ULOG_ERR("Invalid pipeline type!");
262 pipeline = gst_pipeline_new("pipeline");
264 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
267 if (!src || !pipeline)
269 ULOG_ERR("Could not create GstElement!");
273 if (!sink && app->filter != FORMAT_WAV )
275 ULOG_ERR("Could not create GstElement!");
279 ULOG_INFO("Create pipeline");
281 /* add to pipeline and link */
292 ULOG_ERR("Could not create filter GstElement!");
295 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
297 if (!gst_element_link_many (src, filter, sink, NULL))
299 ULOG_ERR("gst_element_link failed for src, filter and sink!");
305 gst_bin_add_many(GST_BIN(pipeline), src, parse, sink, NULL);
306 if (!gst_element_link_many (src, parse, sink, NULL))
308 ULOG_ERR("gst_element_link failed for src, parse and sink!");
326 ULOG_ERR("Could not create filter GstElement!");
329 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
331 if (!gst_element_link_many (src, filter, sink, NULL))
333 ULOG_ERR("gst_element_link failed for src, filter and sink!");
346 gst_bin_add_many(GST_BIN(pipeline), src, sink, NULL);
348 if(!gst_element_link_many(src, sink, NULL))
350 ULOG_ERR("gst_element_link failed for src and sink!");
357 /* set application data */
358 if (type == PIPELINE_REC)
360 app->recPipeline = pipeline;
364 app->playPipeline = pipeline;
365 app->playPipelineType = type;
370 gst_caps_unref(caps);
377 static gboolean destroyPipelines(AppData *data)
379 gboolean ret = FALSE;
381 /* ugly hack with pipeline types, but works though */
382 ret != destroyPipeline(data, PIPELINE_REC);
383 ret != destroyPipeline(data, PIPELINE_PLAY);
387 static gboolean destroyPipeline(AppData *data, PipeLineType type)
391 GstElement *pipeline = NULL;
393 ULOG_INFO("%s() - Stopping playback/recording", G_STRFUNC);
395 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
396 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
397 RECORDER_MSG_STOPPED);
402 pipeline = data->recPipeline;
404 data->recPipeline = NULL;
409 pipeline = data->playPipeline;
411 data->playPipeline = NULL;
416 if (!GST_IS_ELEMENT(pipeline))
419 /* this unallocates everything */
420 gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
422 /* for some reason the state does not update manually */
423 gst_element_get_state(pipeline, &state,
424 &pending, GST_CLOCK_TIME_NONE);
425 pipelineStateChanged(pipeline,
432 gst_object_unref(pipeline);
441 static void pipelineStateChanged (GstElement *element,
447 g_assert(NULL != data);
451 case GST_STATE_PLAYING:
452 if(APPSTATE_RECORDING == getAppState(data))
454 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_RECORDING);
455 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
458 ULOG_INFO("%s() - Recording", G_STRFUNC);
459 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
460 RECORDER_MSG_RECORDING);
462 gtk_widget_set_state(data->buttonRec, GTK_STATE_ACTIVE);
464 if (data->recUpdateId == 0 && gettimeofday(&data->recStartTv, NULL) == 0)
466 data->recUpdateId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, REC_UPDATE_INTERVAL, (GSourceFunc) cbUpdateRecLength, data, NULL);
471 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_PLAYING);
472 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
475 ULOG_INFO("%s() - Playing", G_STRFUNC);
476 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
477 RECORDER_MSG_PLAYING);
478 gtk_widget_set_state(data->buttonPlay, GTK_STATE_ACTIVE);
480 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PAUSE);
486 case GST_STATE_READY:
487 /* hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, "Ready..."); */
488 ULOG_INFO("%s() - Ready", G_STRFUNC);
489 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
493 case GST_STATE_PAUSED:
496 GstFormat fmt = GST_FORMAT_TIME;
497 ULOG_INFO("%s() - Paused", G_STRFUNC);
499 /* if pipeline pos == 0 => stopped, else => paused */
500 if (GST_IS_ELEMENT(data->playPipeline) && gst_element_query_position(data->playPipeline, &fmt, &pos) && pos != 0)
502 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_PAUSED);
503 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
504 RECORDER_MSG_PAUSED);
506 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
511 ULOG_INFO("%s() - Null", G_STRFUNC);
512 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
513 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
514 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
519 ULOG_WARN("%s() - default case", G_STRFUNC);
525 static gboolean cbBus(GstBus *bus,
529 AppData *app = (AppData*)data;
531 switch (GST_MESSAGE_TYPE(message))
533 case GST_MESSAGE_WARNING:
538 gst_message_parse_error (message, &err, &debug);
539 ULOG_WARN("%s() - Warning: %s", G_STRFUNC, err->message);
545 case GST_MESSAGE_ERROR:
550 gst_message_parse_error (message, &err, &debug);
551 ULOG_ERR("%s() - Error: %s", G_STRFUNC, err->message);
555 /* flow through to eos */
558 case GST_MESSAGE_EOS:
560 ULOG_INFO("%s() - eos", G_STRFUNC);
562 switch(getAppState(app))
564 case APPSTATE_PLAYING:
565 /* stop playback after a short break*/
566 g_timeout_add(STOP_DELAY, (GSourceFunc)cbStopPlayback, data);
567 hildon_banner_show_information(GTK_WIDGET(app->mainView), NULL, RECORDER_MSG_STOPPED);
568 gtk_entry_set_text(GTK_ENTRY(app->mainViewData.stateEntry),
569 RECORDER_MSG_STOPPED);
573 case APPSTATE_RECORDING:
574 gst_element_set_state(GST_ELEMENT(app->recPipeline),
576 destroyPipeline(app, PIPELINE_REC);
582 /* destroyPipelines(app); */
588 case GST_MESSAGE_STATE_CHANGED:
594 gst_message_parse_state_changed(message, &old, &new, &pending);
596 pipelineStateChanged(NULL, old, new, pending, app);
602 /* unhandled message */
603 ULOG_WARN("%s() - Unhandled message, type = %d", G_STRFUNC, message->type);
607 /* remove message from the queue */
611 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data)
617 app = (AppData *) data;
619 ULOG_DEBUG("delete_event");
623 destroyPipelines(app);
624 if (app->playPipeline)
625 gst_object_unref(GST_OBJECT(app->playPipeline));
627 if (app->recPipeline)
628 gst_object_unref(GST_OBJECT(app->recPipeline));
633 static gboolean cbCheckPosition (AppData *data)
635 GstFormat fmt = GST_FORMAT_TIME;
636 gint64 pos = 0, len = 0;
638 g_assert(NULL != data);
641 if(!lengthSet && gst_element_query_duration(data->playPipeline, &fmt, &len))
646 size = GST_TIME_TO_SECS(len);
647 setLength(data, size); /* sets lengthEntry and adjustment */
652 /* calculate position */
653 if (gst_element_query_position(data->playPipeline, &fmt, &pos))
655 gdouble time = GST_TIME_TO_SECS(pos);
657 ULOG_DEBUG("pos = %lld, time = %f",
662 gtk_adjustment_set_value(
663 GTK_ADJUSTMENT(data->mainViewData.adjustment),
665 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
668 if (APPSTATE_PLAYING == getAppState(data))
676 static void cbNew(GtkWidget* widget, AppData *data)
678 g_assert(NULL != data);
680 if (!closeFile(data))
683 /* remove pipelines if existing */
684 destroyPipelines(data);
685 ULOG_DEBUG_F("cbNew");
686 /* destroy tmp file */
688 /* clear filenames */
689 g_free(data->openFileName);
690 data->openFileName = NULL;
691 g_free(data->saveFileName);
692 data->saveFileName = NULL;
693 /* data->filter = FORMAT_NONE;*/
694 data->file_format = FORMAT_NONE;
697 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
698 RECORDER_FILE_UNTITLED);
699 setLength(data, 0.0);
700 /* update the display + scale */
701 gtk_adjustment_set_value(GTK_ADJUSTMENT(data->mainViewData.adjustment),
703 gtk_widget_set_sensitive(data->buttonSave, FALSE);
704 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
707 ULOG_DEBUG_F("cbNew end");
710 static void cbOpen(GtkWidget* widget, AppData *data)
712 GtkWidget* dialog = NULL;
713 gchar *tmpfile = NULL;
714 gchar *selected = NULL;
719 GtkFileFilter *filter;
722 ULOG_DEBUG_F("begin");
723 g_assert(NULL != data);
725 if (!closeFile(data))
730 filter = gtk_file_filter_new();
731 gtk_file_filter_add_mime_type(filter, "audio/x-mp3");
734 g_assert(GTK_IS_WINDOW(data->mainView));
736 dialog = hildon_file_chooser_dialog_new_with_properties(
737 GTK_WINDOW(data->mainView),
738 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
739 "file-system-model", NULL,
745 gtk_widget_show_all(dialog);
747 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
749 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
752 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
754 if (dialog != NULL && GTK_IS_WIDGET(dialog))
756 gtk_widget_destroy(dialog);
758 ULOG_DEBUG("%s() - dialog destroyed", G_STRFUNC);
762 if (NULL == selected) /* no file selected */
765 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
767 if (openFile(selected, &format, &tmpfile))
769 ULOG_INFO("%s() - openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
773 /* update filenames */
774 basename = g_path_get_basename(selected);
776 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
779 g_free(data->openFileName);
780 data->openFileName = tmpfile;
781 data->file_format = format;
782 //data->filter = format;
783 g_free(data->saveFileName);
784 data->saveFileName = NULL;
785 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
787 len = guessMediaLength(data);
789 setLength(data, len);
791 setLength(data, 0.0);
793 setFormatString(data, data->file_format);
798 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
799 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
808 openURI(gpointer user_data)
812 gchar *selected = NULL;
814 gchar *tmpfile = NULL;
815 gchar *basename = NULL;
819 data = (AppData *) user_data;
821 if (NULL == data->mimeURI)
824 uri = gnome_vfs_uri_new(data->mimeURI);
825 selected = g_strdup(gnome_vfs_uri_get_path(uri));
827 gnome_vfs_uri_unref(uri);
830 g_free(data->mimeURI);
831 data->mimeURI = NULL;
833 /* TODO: the following is duplicated in cbOpen(), move to a tryOpen() function ? */
835 if (NULL == selected)
838 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
840 if (openFile(selected, &format, &tmpfile))
842 ULOG_INFO("%s: openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
846 /* update filenames */
847 basename = g_path_get_basename(selected);
849 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry), selected);
852 g_free(data->openFileName);
853 data->openFileName = tmpfile;
854 data->file_format = format;
855 //data->filter = format;
856 g_free(data->saveFileName);
857 data->saveFileName = NULL;
858 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
860 len = guessMediaLength(data);
862 setLength(data, len);
864 setLength(data, 0.0);
866 setFormatString(data, data->file_format);
871 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
872 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
880 static void openPlayPipeline( AppData *data )
883 GstFormat fmt = GST_FORMAT_TIME;
887 /* create pipelines */
888 /* check file type */
889 switch (data->file_format)
896 destroyPipelines(data);
897 //data->filter = data->file_format;
898 createPipeline(data, PIPELINE_PLAY);
902 destroyPipelines(data);
903 //data->filter = data->file_format;
904 createPipeline(data, PIPELINE_PLAY_MP3);
909 ULOG_WARN("%s() - unknown file_format", G_STRFUNC);
910 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Unknown filetype!"));
915 if (!GST_IS_ELEMENT(data->playPipeline))
917 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline!"));
921 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_READY);
922 gst_element_get_state(GST_ELEMENT(data->playPipeline), NULL, NULL, GST_CLOCK_TIME_NONE /* or ns */);
924 /* calculate length */
925 if (gst_element_query_duration (data->playPipeline, &fmt, &len))
929 size = GST_TIME_TO_SECS(len);
930 ULOG_INFO("playSize: len:%lld size:%f", len, size);
931 setLength(data, size);
936 setLength(data, 0.0);
941 /* returns whether the action can proceed or should be aborted */
943 closeFile(AppData *data)
951 note = hildon_note_new_confirmation_add_buttons(GTK_WINDOW(data->mainView), _("Save recording?"),
952 _("Yes"), GTK_RESPONSE_YES,
953 _("No"), GTK_RESPONSE_NO,
954 _("Cancel"), GTK_RESPONSE_CANCEL,
957 i = gtk_dialog_run(GTK_DIALOG(note));
958 gtk_widget_destroy(note);
962 case GTK_RESPONSE_CANCEL:
965 case GTK_RESPONSE_NO:
968 case GTK_RESPONSE_YES:
970 cbSaveAs(NULL, data);
974 ULOG_WARN("%s(): unknown response from dialog: %d", G_STRFUNC, i);
980 getFileName(AppData *data)
983 return gtk_entry_get_text(GTK_ENTRY(data->mainViewData.fileNameEntry));
987 static void cbSettings(GtkWidget* widget, AppData *data)
989 settings_edit( widget, data );
992 static void cbEmailing(GtkWidget* widget, AppData *data)
999 g_assert(NULL != data);
1001 if (g_file_test(getFileName(data), G_FILE_TEST_EXISTS))
1003 file = file2uri(getFileName(data));
1004 ULOG_INFO("Emailing: %s", file);
1005 list = g_slist_append(list, file);
1006 result = libmodest_dbus_client_compose_mail(data->osso,
1014 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Emailing failed"));
1021 static void cbSaveAs(GtkWidget* widget, AppData *data)
1023 GtkWidget* dialog = NULL;
1024 const gchar *current;
1025 gchar *selected = NULL;
1027 g_assert(NULL != data);
1029 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1031 current = getFileName(data);
1032 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1034 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1039 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1040 GTK_WINDOW(data->mainView),
1041 GTK_FILE_CHOOSER_ACTION_SAVE));
1043 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog),
1044 get_default_dir() );
1047 gtk_widget_show_all(dialog);
1049 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1051 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1054 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1055 gtk_widget_destroy(dialog);
1057 if (NULL == selected)
1060 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
1062 g_free(data->saveFileName);
1063 data->saveFileName = NULL;
1065 if (saveFile(selected, data->openFileName, data->file_format, &(data->saveFileName)))
1070 g_assert(data->saveFileName);
1072 /* set new title that has the file name */
1073 basename = g_path_get_basename(data->saveFileName);
1074 ULOG_DEBUG("%s() - file '%s' succesfully saved!", G_STRFUNC, data->saveFileName);
1076 /* Houston, we have a kludge:
1077 * for AU files we need to keep the old tmpfile for playback
1078 * for RAW/iLBC files, we can remove the tmpfile and point openFileName to the saved file
1080 ext = getExtension(data->file_format);
1081 if (strcmp(ext, EXTENSION_AU) != 0)
1083 g_free(data->openFileName);
1084 data->openFileName = g_strdup(data->saveFileName);
1087 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1088 data->saveFileName);
1095 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Saving file failed!"));
1101 ULOG_DEBUG("%s() - end", G_STRFUNC);
1104 static void cbRec(GtkWidget* widget, AppData *data)
1106 g_assert(NULL != data);
1108 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1110 if (APPSTATE_READY != getAppState(data))
1112 ULOG_WARN("%s() - state different than READY -> return", G_STRFUNC);
1116 if (!closeFile(data))
1119 /* clear filenames, use tmp file */
1120 g_free(data->openFileName);
1121 data->openFileName = NULL;
1123 g_free(data->saveFileName);
1124 data->saveFileName = NULL;
1126 switch (data->filter)
1129 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1130 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_FILE);
1134 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1135 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMA_FILE);
1139 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1140 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_PCMU_FILE);
1144 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1145 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_WAV_FILE);
1150 data->saveFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1151 data->openFileName = g_strdup_printf("%s/%s", get_default_dir(), DEFAULT_TMP_ILBC_FILE);
1155 ULOG_INFO("%s() - creating pipelines", G_STRFUNC);
1156 /* start recording */
1157 /* create related pipelines */
1158 if (createPipeline(data, PIPELINE_REC))
1160 ULOG_INFO("%s() - starting recording", G_STRFUNC);
1161 /* start recording */
1162 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1165 /* update display */
1166 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.fileNameEntry),
1167 data->saveFileName);
1169 setAppState(data, APPSTATE_RECORDING);
1170 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1171 data->file_format = data->filter;
1172 setFormatString(data, data->file_format);
1176 ULOG_ERR("Could not create rec pipeline!");
1177 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline"));
1178 setAppState(data, APPSTATE_READY);
1181 ULOG_DEBUG("%s() - end", G_STRFUNC);
1184 static void cbPlay(GtkWidget* widget, AppData *data)
1186 const gchar * file = NULL;
1188 g_assert(NULL != data);
1190 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1192 file = getFileName(data);
1193 if (NULL == data->openFileName || NULL == file || strcmp(file, RECORDER_FILE_UNTITLED) == 0)
1195 ULOG_WARN("%s() - nothing to play", G_STRFUNC);
1199 openPlayPipeline(data);
1201 if (APPSTATE_PLAYING == getAppState(data))
1203 if (GST_IS_ELEMENT(data->playPipeline))
1205 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_PAUSED);
1206 setAppState(data, APPSTATE_READY);
1211 if (APPSTATE_READY != getAppState(data))
1213 ULOG_WARN("%s() - state different than PLAYING or READY -> return", G_STRFUNC);
1217 ULOG_INFO("filename %s", file);
1219 if (! GST_IS_ELEMENT(data->playPipeline))
1221 ULOG_WARN("%s() - playPipeline does not exist", G_STRFUNC);
1225 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1228 setAppState(data, APPSTATE_PLAYING);
1230 g_timeout_add(PLAY_UPDATE_INTERVAL, (GSourceFunc)cbCheckPosition, data);
1232 ULOG_DEBUG("%s() - end", G_STRFUNC);
1235 static void cbStop(GtkWidget* widget, AppData *data)
1237 g_assert(NULL != data);
1239 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1241 /* check if we are playing/recording */
1243 /* stop playing or recording */
1244 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
1245 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1246 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
1248 /* destroy related pipeline */
1249 switch(getAppState(data))
1251 case APPSTATE_PLAYING:
1252 /* don't destroy the playing pipeline. Instead, set the pipeline to PAUSED */
1253 /* destroyPipeline(data, PIPELINE_PLAY); */
1254 ULOG_INFO("%s() - Setting playPipeline state to PAUSED", G_STRFUNC);
1255 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1258 case APPSTATE_READY:
1259 /* seek to zero, but not for PCM pipeline */
1260 /* if (data->playPipelineType == PIPELINE_PLAY || seekToZero(data, GST_ELEMENT(data->playPipeline))) */
1261 if ( !GST_IS_ELEMENT(data->playPipeline) || seekToZero(data, GST_ELEMENT(data->playPipeline)))
1263 gtk_adjustment_set_value(
1264 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1265 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1266 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.stateEntry),
1267 RECORDER_MSG_STOPPED);
1271 case APPSTATE_RECORDING:
1274 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1276 destroyPipeline(data, PIPELINE_REC);
1277 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1278 data->saved = FALSE;
1280 len = guessMediaLength(data);
1282 setLength(data, len);
1288 /* seekToZero(data, GST_ELEMENT(data->playPipeline)); */
1289 /* should not come here */
1293 setAppState(data, APPSTATE_READY);
1295 ULOG_DEBUG("%s() - end", G_STRFUNC);
1299 /* ui construction functions */
1301 static GtkWidget* createToolBar(AppData *data)
1303 GtkToolbar* toolBar = NULL;
1305 GtkToolItem* new = NULL;
1306 GtkToolItem* open = NULL;
1307 GtkToolItem* save = NULL;
1308 GtkToolItem* saveas = NULL;
1309 GtkToolItem* sep = NULL;
1310 GtkToolItem* play = NULL;
1311 GtkToolItem* rec = NULL;
1312 GtkToolItem* stop = NULL;
1314 /* create buttons */
1315 new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
1316 open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
1317 save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
1318 data->buttonSave = GTK_WIDGET(save);
1319 saveas = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE_AS);
1320 data->buttonSaveAs = GTK_WIDGET(saveas);
1321 gtk_widget_set_sensitive(data->buttonSave, FALSE);
1322 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
1325 gtk_tool_item_set_expand( GTK_TOOL_ITEM(new), TRUE );
1326 gtk_tool_item_set_expand( GTK_TOOL_ITEM(open), TRUE );
1327 gtk_tool_item_set_expand( GTK_TOOL_ITEM(saveas), TRUE );
1329 rec = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_RECORD);
1330 data->buttonRec = GTK_WIDGET(rec);
1331 play = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
1332 data->buttonPlay = GTK_WIDGET(play);
1333 stop = gtk_tool_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
1335 gtk_tool_item_set_expand( GTK_TOOL_ITEM(rec), TRUE );
1336 gtk_tool_item_set_expand( GTK_TOOL_ITEM(play), TRUE );
1337 gtk_tool_item_set_expand( GTK_TOOL_ITEM(stop), TRUE );
1339 /* create separator */
1340 sep = gtk_separator_tool_item_new();
1342 /* create the toolbar itself */
1343 toolBar = GTK_TOOLBAR(gtk_toolbar_new());
1345 /* add items to toolbar */
1346 gtk_toolbar_insert(toolBar, new, -1);
1347 gtk_toolbar_insert(toolBar, open, -1);
1348 gtk_toolbar_insert(toolBar, saveas, -1);
1349 gtk_toolbar_insert(toolBar, sep, -1);
1350 gtk_toolbar_insert(toolBar, rec, -1);
1351 gtk_toolbar_insert(toolBar, play, -1);
1352 gtk_toolbar_insert(toolBar, stop, -1);
1354 /* connect signals */
1355 g_signal_connect(G_OBJECT(new), "clicked",
1358 g_signal_connect(G_OBJECT(open), "clicked",
1361 g_signal_connect(G_OBJECT(saveas), "clicked",
1362 G_CALLBACK(cbSaveAs),
1364 g_signal_connect(G_OBJECT(rec), "clicked",
1367 g_signal_connect(G_OBJECT(play), "clicked",
1370 g_signal_connect(G_OBJECT(stop), "clicked",
1374 return GTK_WIDGET(toolBar);
1378 static void cbItemGroupChanged( gpointer data )
1380 AppData* app = (AppData* ) data;
1381 GValue active ={G_TYPE_INVALID};
1384 g_value_init(&active, G_TYPE_INT);
1386 g_object_get_property(G_OBJECT(app->radio_pcma), "active", &active);
1387 pcma = g_value_get_int(&active);
1388 g_object_get_property(G_OBJECT(app->radio_ilbc), "active", &active);
1389 ilbc = g_value_get_int(&active);
1390 g_object_get_property(G_OBJECT(app->radio_pcm), "active", &active);
1391 pcm = g_value_get_int(&active);
1393 ULOG_INFO("change type pcma=%d ilbc=%d pcm=%d",pcma, ilbc, pcm);
1395 app->filter = FORMAT_PCMA;
1396 else if ( ilbc == 1 )
1397 app->filter = FORMAT_ILBC;
1398 else if ( pcm == 1 )
1399 app->filter = FORMAT_WAV;
1403 ULOG_INFO("filter type=%d", app->filter);
1406 static void cbItemClose(GtkWidget *widget, gpointer data)
1410 if (!closeFile(data))
1416 /* Create the menu items needed for the main view */
1417 static void createMenu( AppData *data )
1419 HildonAppMenu *menu;
1420 GtkWidget *button_email;
1422 menu = HILDON_APP_MENU( hildon_app_menu_new() );
1423 button_email = hildon_gtk_button_new(HILDON_SIZE_AUTO);
1424 gtk_button_set_label( GTK_BUTTON(button_email), "Send via email");
1425 hildon_app_menu_append( menu, GTK_BUTTON(button_email));
1427 g_signal_connect( G_OBJECT( button_email ), "clicked",
1428 GTK_SIGNAL_FUNC (cbEmailing), data);
1431 gtk_widget_show_all( GTK_WIDGET(menu));
1433 hildon_window_set_app_menu(HILDON_WINDOW(data->mainView), menu);
1435 data->filter = get_default_filter();
1440 evKeypress(GtkWidget *widget, GdkEventKey *ev, AppData *appdata)
1446 cbRec(widget, appdata);
1449 cbPlay(widget, appdata);
1452 cbStop(widget, appdata);
1462 gboolean maemo_recorder_ui_new(AppData *data)
1464 HildonProgram *app = NULL;
1465 HildonWindow *window = NULL;
1466 GtkWidget *hbox = NULL;
1467 GtkWidget *vbox = NULL;
1468 GtkWidget *label = NULL;
1469 GtkWidget *entry1 = NULL;
1470 GtkWidget *entry2 = NULL;
1471 GtkWidget *entry3 = NULL;
1472 GtkWidget *toolBar = NULL;
1473 GtkWidget *infohbox = NULL;
1474 GtkWidget *table = NULL;
1475 GtkWidget *scale = NULL;
1476 GtkObject *adjustment = NULL;
1478 g_assert(NULL != data);
1480 app = HILDON_PROGRAM(hildon_program_get_instance());
1481 g_set_application_name(RECORDER_APP_TITLE);
1484 window = HILDON_WINDOW(hildon_window_new());
1486 hildon_program_add_window(app, window);
1488 /* content for main view */
1490 /* create vbox, divides control area and view area */
1491 vbox = gtk_vbox_new(FALSE, 0);
1493 /* create hbox to divide control area */
1494 hbox = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
1496 /* create toolbar */
1497 toolBar = createToolBar(data);
1499 /* create table for labels */
1500 table = gtk_table_new (4, 2, FALSE);
1501 gtk_table_set_homogeneous(GTK_TABLE(table), FALSE);
1503 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
1504 gtk_table_set_col_spacings (GTK_TABLE (table), HILDON_MARGIN_TRIPLE);
1506 label = gtk_label_new_with_mnemonic(_("Filename:"));
1507 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1508 gtk_table_attach_defaults (GTK_TABLE (table),
1512 entry1 = gtk_entry_new();
1513 gtk_entry_set_has_frame(GTK_ENTRY(entry1), FALSE);
1514 gtk_entry_set_text(GTK_ENTRY (entry1), _(RECORDER_FILE_UNTITLED));
1515 gtk_entry_set_editable(GTK_ENTRY(entry1), FALSE);
1516 gtk_table_attach_defaults(GTK_TABLE (table), entry1, 1, 2, 0, 1);
1517 gtk_label_set_mnemonic_widget(GTK_LABEL (label), entry1);
1519 label = gtk_label_new_with_mnemonic (_("Length:"));
1520 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1521 gtk_table_attach_defaults (GTK_TABLE (table),
1525 entry2 = gtk_entry_new ();
1526 gtk_entry_set_has_frame(GTK_ENTRY(entry2), FALSE);
1527 gtk_entry_set_text (GTK_ENTRY (entry2), "0:00.00");
1528 gtk_entry_set_editable(GTK_ENTRY(entry2), FALSE);
1529 gtk_table_attach_defaults (GTK_TABLE (table), entry2, 1, 2, 1, 2);
1530 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry2);
1532 /* audio format field */
1533 label = gtk_label_new_with_mnemonic(_("Format:"));
1534 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1535 gtk_table_attach_defaults (GTK_TABLE (table),
1539 entry3 = gtk_entry_new();
1540 gtk_entry_set_has_frame(GTK_ENTRY(entry3), FALSE);
1541 gtk_entry_set_width_chars(GTK_ENTRY(entry3), 40);
1542 gtk_entry_set_text (GTK_ENTRY (entry3), RECORDER_FMT_STRING_NONE);
1543 gtk_entry_set_editable(GTK_ENTRY(entry3), FALSE);
1544 data->mainViewData.formatEntry = GTK_WIDGET(entry3);
1546 gtk_table_attach_defaults (GTK_TABLE (table), entry3, 1, 2, 2, 3);
1547 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry3);
1549 label = gtk_label_new_with_mnemonic(_("State:"));
1550 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1551 gtk_table_attach_defaults (GTK_TABLE (table),
1555 entry3 = gtk_entry_new ();
1556 gtk_entry_set_has_frame(GTK_ENTRY(entry3), FALSE);
1557 gtk_entry_set_text (GTK_ENTRY (entry3), RECORDER_MSG_READY);
1558 gtk_entry_set_editable(GTK_ENTRY(entry3), FALSE);
1559 gtk_table_attach_defaults (GTK_TABLE (table), entry3, 1, 2, 3, 4);
1560 gtk_label_set_mnemonic_widget(GTK_LABEL (label), entry3);
1562 adjustment = gtk_adjustment_new (0.00,
1569 scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1571 /* gtk_table_attach_defaults (GTK_TABLE (table),
1575 /* connect signals */
1576 g_signal_connect(G_OBJECT(adjustment), "value-changed", G_CALLBACK(cbUserSeek), data);
1577 g_signal_connect(G_OBJECT(scale), "format-value", G_CALLBACK(cbFormatSeekbarValue), data);
1578 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(cbDestroy), data);
1579 g_signal_connect(G_OBJECT(window), "key-press-event",
1580 G_CALLBACK(evKeypress), data);
1582 /* packing the view */
1583 gtk_container_add (GTK_CONTAINER(window), vbox);
1584 infohbox = gtk_hbox_new(FALSE, 0);
1585 gtk_box_pack_start (GTK_BOX(infohbox), table, FALSE, TRUE, 0);
1586 gtk_box_pack_start (GTK_BOX(vbox), infohbox, FALSE, TRUE, 0);
1587 gtk_box_pack_start (GTK_BOX(vbox), scale, FALSE, FALSE, 0);
1588 /* gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 0); */
1590 hildon_window_add_toolbar(window, GTK_TOOLBAR(toolBar));
1592 /* store needed widgets */
1594 data->mainView = window;
1595 data->mainViewData.toolBar = GTK_WIDGET(toolBar);
1596 data->mainViewData.fileNameEntry = GTK_WIDGET(entry1);
1597 data->mainViewData.lengthEntry = GTK_WIDGET(entry2);
1598 data->mainViewData.stateEntry = GTK_WIDGET(entry3);
1599 data->mainViewData.adjustment = GTK_OBJECT(adjustment);
1602 gtk_widget_show_all(GTK_WIDGET(window));
1610 maemo_recorder_mime_open(gpointer user_data, gint argc, gchar **argv)
1614 ULOG_DEBUG("%s with %d arguments", __FUNCTION__, argc);
1619 g_assert(user_data);
1620 data = (AppData *) user_data;
1622 if (argv[0] != NULL)
1624 ULOG_DEBUG("request to open %s", argv[0]);
1625 g_free(data->mimeURI);
1626 data->mimeURI = g_strdup(argv[0]);
1627 g_idle_add(openURI, (gpointer) data);
1628 gtk_window_present(GTK_WINDOW(data->mainView));
1632 static void seekToTime(GstElement *pipeline, gdouble secs)
1634 g_assert(NULL != pipeline);
1635 ULOG_DEBUG("Seeking to: %.2f", secs);
1637 /* time must be nanoseconds */
1638 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1639 GST_SEEK_TYPE_SET, (gint64) (secs * GST_SECOND),
1640 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1642 ULOG_WARN("seekToTime failed!");
1645 ULOG_DEBUG("seekToTime succeeded");
1648 static gboolean seekToZero(AppData *data, GstElement *pipeline)
1651 g_assert(NULL != pipeline);
1652 ULOG_DEBUG("Seeking to zero");
1654 /* time must be nanoseconds */
1655 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1656 GST_SEEK_TYPE_SET, (gint64) 0,
1657 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1659 ULOG_ERR("seekToZero failed! Trying to destroy and re-create pipeline");
1660 plType = data->playPipelineType;
1662 /* gst_element_set_state(pipeline, GST_STATE_READY); */
1663 destroyPipeline(data, plType);
1664 return createPipeline(data, plType);
1667 ULOG_DEBUG("seekToZero succeeded");
1672 setFormatString(AppData *data, AudioFormat afmt)
1677 /* these are pretty much always the same */
1679 gint rate = DEFAULT_RATE; /* 8000 */
1683 g_assert(GTK_IS_ENTRY(data->mainViewData.formatEntry));
1688 format = FORMAT_NAME_PCMA;
1691 format = FORMAT_NAME_PCMU;
1694 format = FORMAT_NAME_ILBC;
1697 /* TODO: we can play wavs with many sampling rates, 2 channels */
1698 /* we really should migrate to the better format spec */
1700 format = FORMAT_NAME_WAV;
1704 format = FORMAT_NAME_PCM;
1708 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.formatEntry), RECORDER_FMT_STRING_NONE);
1712 str = g_strdup_printf("%s, %d %s, %d Hz, %d %s", format, channels, _("ch"), rate, bits, _("bits"));
1713 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.formatEntry), str);
1717 static void setLength(AppData *data, gdouble secs)
1727 g_object_set(G_OBJECT(data->mainViewData.adjustment),
1730 gtk_adjustment_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1736 secs -= mins * 60.0;
1739 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
1742 ULOG_INFO("Setting length to %s", tmp);
1744 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
1749 static gdouble guessMediaLength(AppData *data)
1751 GnomeVFSFileSize size = 0;
1752 gdouble bitrate = 0.0;
1755 if (data->openFileName)
1756 size = getFileLength(data->openFileName);
1763 ULOG_DEBUG("file size: %llu bytes", size);
1765 switch (data->file_format)
1768 bitrate = ILBC_BITRATE_30;
1773 bitrate = PCMA_BITRATE;
1783 len = (((gdouble) size) * 8.0) / (bitrate);
1784 ULOG_DEBUG("guessed media length: %.2f secs", len);
1789 static GstCaps *createCapsFilter(AudioFormat format)
1794 return gst_caps_new_simple(
1796 "rate", G_TYPE_INT, ILBC_RATE,
1797 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1798 "mode", G_TYPE_INT, 30, /* 30 ms frames */
1801 return gst_caps_new_simple(
1803 "rate", G_TYPE_INT, DEFAULT_RATE,
1804 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1807 return gst_caps_new_simple(
1809 "rate", G_TYPE_INT, DEFAULT_RATE,
1810 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1814 return gst_caps_new_simple(
1816 "rate", G_TYPE_INT, PCM_RATE,
1817 "signed", G_TYPE_BOOLEAN, TRUE,
1818 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1819 "endianness", G_TYPE_INT, PCM_ENDIANNESS,
1820 "width", G_TYPE_INT, PCM_WIDTH,
1821 "depth", G_TYPE_INT, PCM_DEPTH,
1824 ULOG_WARN("%s(): creating ANY caps", G_STRFUNC);
1825 return gst_caps_new_any();
1829 static gboolean cbStopPlayback(AppData *data)
1832 ULOG_INFO("Stopping playback");
1834 g_assert(data != NULL);
1836 ret = gst_element_set_state(GST_ELEMENT(data->playPipeline),
1838 if (seekToZero(data, GST_ELEMENT(data->playPipeline)))
1840 gtk_adjustment_set_value(
1841 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1842 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1844 setAppState(data, APPSTATE_READY);
1845 gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(data->buttonPlay), GTK_STOCK_MEDIA_PLAY);
1846 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1851 static void cbUserSeek(GtkAdjustment *adjustment, gpointer data)
1853 /*ULOG_INFO("cbUserSeek");*/
1856 g_return_if_fail(data != NULL);
1857 app = (AppData *) data;
1859 if (getAppState(app) != APPSTATE_READY || NULL == app->playPipeline)
1862 seekToTime(app->playPipeline, gtk_adjustment_get_value(adjustment));
1865 static gchar *cbFormatSeekbarValue(GtkScale *scale, gdouble value)
1867 /* ULOG_INFO("cbFormatSeekbarValue");*/
1869 gint digits = gtk_scale_get_digits(scale);
1874 value -= mins * 60.0;
1875 return g_strdup_printf("%d:%0*.*f", mins, digits + 3, digits, value);
1878 return g_strdup_printf("%0.*f", digits, value);
1881 static gboolean cbUpdateRecLength(AppData *data)
1888 if (gettimeofday(&tv, NULL) != 0)
1891 secs = tv.tv_sec - data->recStartTv.tv_sec;
1892 secs += ((tv.tv_usec - data->recStartTv.tv_usec) / 1000000.0);
1897 secs -= mins * 60.0;
1898 tmp = g_strdup_printf("%u:%05.2f", mins, secs);
1901 tmp = g_strdup_printf("%0.2f", secs);
1903 gtk_entry_set_text(GTK_ENTRY(data->mainViewData.lengthEntry),
1907 if (getAppState(data) == APPSTATE_RECORDING)
1910 data->recUpdateId = 0;