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 <glib/gstdio.h>
37 #include "maemo-recorder.h"
38 #include "maemo-recorder-ui.h"
39 #include "maemo-recorder-file.h"
42 #define DEFAULT_REC_BLOCKSIZE "160"
44 #define STOP_DELAY 500
45 #define REC_UPDATE_INTERVAL 500
46 #define PLAY_UPDATE_INTERVAL 200
50 #define GST_TIME_MINS(t) \
51 (guint) ((((GstClockTime)(t)) / (GST_SECOND * 60)) % 60)
52 #define GST_TIME_SECS(t) \
53 (guint) ((((GstClockTime)(t)) / GST_SECOND) % 60)
54 #define GST_TIME_TO_SECS(t) \
55 (gdouble) (((gdouble)(t)) / (gdouble) GST_SECOND) /* GST_SECOND should be 1e9 */
56 #define GST_TIME_MSECS(t) \
57 (guint) (((GstClockTime)(t)) % GST_SECOND)
59 #define RECORDER_APP_TITLE "Recorder"
60 #define RECORDER_MSG_READY _("Ready")
61 #define RECORDER_MSG_STOPPED _("Stopped")
62 #define RECORDER_MSG_PAUSED _("Paused")
63 #define RECORDER_MSG_PLAYING _("Playing")
64 #define RECORDER_MSG_RECORDING _("Recording")
65 #define RECORDER_FILE_UNTITLED _("Untitled")
67 #define RECORDER_FMT_STRING_NONE _("N/A")
69 /* general enumerations */
84 /* function prototypes */
86 static gboolean cbBus (GstBus *bus,
90 static void pipelineStateChanged (GstElement *element,
96 static void seekToTime(GstElement *pipeline, gdouble secs);
97 static gboolean seekToZero(AppData *data, GstElement *pipeline);
98 static void setLength(AppData *data, gdouble secs);
99 static void setFormatString(AppData *data, AudioFormat afmt);
100 static gboolean cbStopPlayback(AppData *data);
101 static void cbStop(GtkWidget* widget, GdkEventButton *event, AppData *data);
102 static void cbPlay(GtkWidget* widget, GdkEventButton *event, AppData *data);
103 static void cbRec(GtkWidget* widget, GdkEventButton *event, AppData *data);
104 static void cbNew(GtkWidget* widget, AppData *data);
105 static void cbOpen(GtkWidget* widget, AppData *data);
106 /*static void cbSave(GtkWidget* widget, AppData *data);*/
107 static void cbSaveAs(GtkWidget* widget, AppData *data);
108 static void createMenu( AppData *data );
109 static gboolean createPipeline(AppData *app, PipeLineType type);
110 static void openPlayPipeline( AppData *data );
111 static gboolean destroyPipeline(AppData *data, PipeLineType type);
112 static gboolean destroyPipelines(AppData *data);
113 static void cbItemGroupChanged(gpointer data);
114 static gboolean cbUpdateRecLength(AppData *data);
115 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data);
116 static gboolean openURI(gpointer user_data);
117 static gboolean closeFile(AppData *data);
118 static const gchar *getFileName(AppData *data);
119 static gdouble guessMediaLength(AppData *data);
120 static GstCaps *createCapsFilter(AudioFormat format);
121 static gboolean evKeypress(GtkWidget *widget, GdkEventKey *ev, AppData *appdata);
122 static gboolean cbScaleRelease(GtkWidget *widget, GdkEventButton *ev, gpointer data);
124 static gboolean lengthSet = FALSE;
126 static gboolean createPipeline(AppData *app, PipeLineType type)
128 GstElement *src = NULL;
129 GstElement *sink = NULL;
130 GstElement *filter = NULL;
131 GstElement *pipeline = NULL;
132 GstElement *parse = NULL;
133 GstElement *bin = NULL;
134 GstCaps *caps = NULL;
136 g_assert(NULL != app);
138 /* create elements */
141 case PIPELINE_PLAY_MP3:
142 ULOG_INFO("mp3 playback - queue");
143 bin = gst_element_factory_make ("playbin2", "bin");
144 gchar* uri = g_strdup_printf("file://%s", app->openFileName);
145 g_object_set(G_OBJECT(bin),
149 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (bin)),
152 app->playPipeline = bin;
153 app->playPipelineType = type;
159 src = gst_element_factory_make ("filesrc", "source");
160 /* we need also a filter to modify caps */
161 filter = gst_element_factory_make("capsfilter", "filter");
165 ULOG_INFO("using ilbc sink");
166 sink = gst_element_factory_make ("dspilbcsink", "sink");
172 ULOG_INFO("using pcm sink");
173 sink = gst_element_factory_make ("pulsesink", "sink");
177 ULOG_INFO("using wavparse & pcm sink");
178 bin = gst_element_factory_make ("playbin2", "bin");
179 gchar* uri = g_strdup_printf("file://%s", app->openFileName);
180 g_object_set(G_OBJECT(bin),
185 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (bin)),
188 app->playPipeline = bin;
189 app->playPipelineType = type;
198 g_object_set(G_OBJECT(src),
199 "location", app->openFileName,
202 caps = createCapsFilter(app->filter);
203 g_object_set(G_OBJECT(filter),
212 ULOG_INFO("using ilbc source");
213 src = gst_element_factory_make("dspilbcsrc", "source");
214 g_object_set(G_OBJECT(src),
223 ULOG_INFO("using pcm source");
224 src = gst_element_factory_make("pulsesrc", "source");
225 /*g_object_set(G_OBJECT (src),
226 "blocksize", DEFAULT_REC_BLOCKSIZE,
232 ULOG_INFO("using pcm source & wavenc");
233 src = gst_element_factory_make("pulsesrc", "source");
234 parse = gst_element_factory_make("wavenc", "enc");
238 ULOG_WARN("Unknown filter type!");
242 filter = gst_element_factory_make("capsfilter", "filter");
243 caps = createCapsFilter(app->filter);
244 g_object_set(G_OBJECT(filter),
248 sink = gst_element_factory_make("filesink", "sink");
250 g_object_set(G_OBJECT(sink),
251 "location", app->saveFileName,
256 ULOG_ERR("Invalid pipeline type!");
260 pipeline = gst_pipeline_new("pipeline");
262 gst_bus_add_watch(gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
265 if (!src || !pipeline)
267 ULOG_ERR("Could not create GstElement!");
271 if (!sink && app->filter != FORMAT_WAV )
273 ULOG_ERR("Could not create GstElement!");
277 ULOG_INFO("Create pipeline");
279 /* add to pipeline and link */
290 ULOG_ERR("Could not create filter GstElement!");
293 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
295 if (!gst_element_link_many (src, filter, sink, NULL))
297 ULOG_ERR("gst_element_link failed for src, filter and sink!");
303 gst_bin_add_many(GST_BIN(pipeline), src, filter, parse, sink, NULL);
304 if (!gst_element_link_many (src, filter, parse, sink, NULL))
306 ULOG_ERR("gst_element_link failed for src, parse and sink!");
324 ULOG_ERR("Could not create filter GstElement!");
327 gst_bin_add_many(GST_BIN(pipeline), src, filter, sink, NULL);
329 if (!gst_element_link_many (src, filter, sink, NULL))
331 ULOG_ERR("gst_element_link failed for src, filter and sink!");
344 gst_bin_add_many(GST_BIN(pipeline), src, sink, NULL);
346 if(!gst_element_link_many(src, sink, NULL))
348 ULOG_ERR("gst_element_link failed for src and sink!");
355 /* set application data */
356 if (type == PIPELINE_REC)
358 app->recPipeline = pipeline;
362 app->playPipeline = pipeline;
363 app->playPipelineType = type;
368 gst_caps_unref(caps);
375 static gboolean destroyPipelines(AppData *data)
377 gboolean ret = FALSE;
379 /* ugly hack with pipeline types, but works though */
380 ret != destroyPipeline(data, PIPELINE_REC);
381 ret != destroyPipeline(data, PIPELINE_PLAY);
385 static gboolean destroyPipeline(AppData *data, PipeLineType type)
389 GstElement *pipeline = NULL;
391 ULOG_INFO("%s() - Stopping playback/recording", G_STRFUNC);
393 //hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_STOPPED);
394 gtk_label_set_text(GTK_LABEL(data->mainViewData.stateEntry), "");
395 gtk_widget_set_sensitive(data->buttonRec, TRUE);
400 pipeline = data->recPipeline;
402 data->recPipeline = NULL;
407 pipeline = data->playPipeline;
409 data->playPipeline = NULL;
414 if (!GST_IS_ELEMENT(pipeline))
417 /* this unallocates everything */
418 gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_NULL);
420 /* for some reason the state does not update manually */
421 gst_element_get_state(pipeline, &state,
422 &pending, GST_CLOCK_TIME_NONE);
423 pipelineStateChanged(pipeline,
430 gst_object_unref(pipeline);
439 static void pipelineStateChanged (GstElement *element,
445 g_assert(NULL != data);
449 case GST_STATE_PLAYING:
450 if(APPSTATE_RECORDING == getAppState(data))
452 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_RECORDING);
453 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
456 ULOG_INFO("%s() - Recording", G_STRFUNC);
457 gtk_label_set_text(GTK_LABEL(data->mainViewData.stateEntry),
458 RECORDER_MSG_RECORDING);
460 gtk_widget_set_state(data->buttonRec, GTK_STATE_ACTIVE);
462 if (data->recUpdateId == 0)
464 data->recUpdateId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, REC_UPDATE_INTERVAL, (GSourceFunc) cbUpdateRecLength, data, NULL);
469 gchar *tmp = g_strdup_printf("%s...", RECORDER_MSG_PLAYING);
470 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, tmp);
473 ULOG_INFO("%s() - Playing", G_STRFUNC);
474 gtk_label_set_text(GTK_LABEL(data->mainViewData.stateEntry),
475 RECORDER_MSG_PLAYING);
476 gtk_widget_set_state(data->buttonPlay, GTK_STATE_ACTIVE);
481 case GST_STATE_READY:
482 /* hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, "Ready..."); */
483 ULOG_INFO("%s() - Ready", G_STRFUNC);
484 gtk_label_set_text(GTK_LABEL(data->mainViewData.stateEntry), "");
487 case GST_STATE_PAUSED:
490 GstFormat fmt = GST_FORMAT_TIME;
491 ULOG_INFO("%s() - Paused", G_STRFUNC);
493 /* if pipeline pos == 0 => stopped, else => paused */
494 if (GST_IS_ELEMENT(data->playPipeline) && gst_element_query_position(data->playPipeline, &fmt, &pos) && pos != 0)
496 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_PAUSED);
497 gtk_label_set_text(GTK_LABEL(data->mainViewData.stateEntry),
498 RECORDER_MSG_PAUSED);
500 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
505 ULOG_INFO("%s() - Null", G_STRFUNC);
506 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
507 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
512 ULOG_WARN("%s() - default case", G_STRFUNC);
518 static gboolean cbBus(GstBus *bus,
522 AppData *app = (AppData*)data;
524 switch (GST_MESSAGE_TYPE(message))
526 case GST_MESSAGE_WARNING:
531 gst_message_parse_warning (message, &err, &debug);
532 ULOG_WARN("%s() - Warning: %s", G_STRFUNC, err->message);
539 case GST_MESSAGE_ERROR:
544 gst_message_parse_error (message, &err, &debug);
545 ULOG_ERR("%s() - Error: %s", G_STRFUNC, err->message);
550 /* flow through to eos */
553 case GST_MESSAGE_EOS:
555 ULOG_INFO("%s() - eos", G_STRFUNC);
557 switch(getAppState(app))
559 case APPSTATE_PLAYING:
560 /* stop playback after a short break*/
561 g_timeout_add(STOP_DELAY, (GSourceFunc)cbStopPlayback, data);
562 //hildon_banner_show_information(GTK_WIDGET(app->mainView), NULL, RECORDER_MSG_STOPPED);
563 gtk_label_set_text(GTK_LABEL(app->mainViewData.stateEntry),
568 case APPSTATE_RECORDING:
569 gst_element_set_state(GST_ELEMENT(app->recPipeline),
571 destroyPipeline(app, PIPELINE_REC);
573 setAppState(data, APPSTATE_READY);
578 /* destroyPipelines(app); */
584 case GST_MESSAGE_ASYNC_DONE:
585 case GST_MESSAGE_STATE_CHANGED:
591 gst_message_parse_state_changed(message, &old, &new, &pending);
593 pipelineStateChanged(NULL, old, new, pending, app);
599 /* unhandled message */
600 ULOG_WARN("%s() - Unhandled message, type = %d", G_STRFUNC, message->type);
604 /* remove message from the queue */
608 static void cbDestroy(GtkWidget* widget, GdkEvent *event, gpointer data)
614 app = (AppData *) data;
616 ULOG_DEBUG("delete_event");
619 destroyPipelines(app);
620 if (app->playPipeline)
621 gst_object_unref(GST_OBJECT(app->playPipeline));
623 if (app->recPipeline)
624 gst_object_unref(GST_OBJECT(app->recPipeline));
629 static gboolean cbCheckPosition (AppData *data)
631 GstFormat fmt = GST_FORMAT_TIME;
632 gint64 pos = 0, len = 0;
634 g_assert(NULL != data);
637 if(!lengthSet && gst_element_query_duration(data->playPipeline, &fmt, &len))
642 size = GST_TIME_TO_SECS(len);
643 setLength(data, size); /* sets lengthEntry and adjustment */
648 /* calculate position */
649 if (gst_element_query_position(data->playPipeline, &fmt, &pos))
651 gdouble time = GST_TIME_TO_SECS(pos);
655 ULOG_DEBUG("pos = %lld, time = %f",
660 gtk_adjustment_set_value(
661 GTK_ADJUSTMENT(data->mainViewData.adjustment),
663 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
670 tmp = g_strdup_printf("%02u:%02d", mins, (int)time);
672 gtk_label_set_text(GTK_LABEL(data->mainViewData.ctime),
678 if (APPSTATE_PLAYING == getAppState(data))
686 static void cbNew(GtkWidget* widget, AppData *data)
688 g_assert(NULL != data);
690 if (!closeFile(data))
693 /* remove pipelines if existing */
694 if (APPSTATE_PLAYING == getAppState(data) || APPSTATE_RECORDING == getAppState(data)) {
695 cbStop(widget, NULL, data);
696 destroyPipelines(data);
699 setAppState(data, APPSTATE_READY);
700 ULOG_DEBUG_F("cbNew");
701 /* destroy tmp file */
703 /* clear filenames */
704 g_free(data->openFileName);
705 data->openFileName = NULL;
706 g_free(data->saveFileName);
707 data->saveFileName = NULL;
708 /* data->filter = FORMAT_NONE;*/
709 data->file_format = FORMAT_NONE;
712 gtk_label_set_text(GTK_LABEL(data->mainViewData.fileNameEntry),
713 RECORDER_FILE_UNTITLED);
714 setLength(data, 0.0);
715 /* update the display + scale */
716 gtk_adjustment_set_value(GTK_ADJUSTMENT(data->mainViewData.adjustment),
718 gtk_label_set_text(GTK_LABEL(data->mainViewData.ctime), "00:00");
719 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
722 ULOG_DEBUG_F("cbNew end");
725 static void cbOpen(GtkWidget* widget, AppData *data)
727 GtkWidget* dialog = NULL;
728 gchar *tmpfile = NULL;
729 gchar *selected = NULL;
734 GtkFileFilter *filter;
737 ULOG_DEBUG_F("begin");
738 g_assert(NULL != data);
740 if (!closeFile(data))
742 if (APPSTATE_PLAYING == getAppState(data) || APPSTATE_RECORDING == getAppState(data)) {
743 cbStop(widget, NULL, data);
744 destroyPipelines(data);
749 filter = gtk_file_filter_new();
750 gtk_file_filter_add_mime_type(filter, "audio/x-mp3");
753 g_assert(GTK_IS_WINDOW(data->mainView));
755 dialog = hildon_file_chooser_dialog_new_with_properties(
756 GTK_WINDOW(data->mainView),
757 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
758 "file-system-model", NULL,
764 gtk_widget_show_all(dialog);
766 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
768 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
771 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
773 if (dialog != NULL && GTK_IS_WIDGET(dialog))
775 gtk_widget_destroy(dialog);
777 ULOG_DEBUG("%s() - dialog destroyed", G_STRFUNC);
781 if (NULL == selected)
783 /* no file selected */
784 if (!g_file_test(getFileName(data), G_FILE_TEST_EXISTS))
791 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
793 if (openFile(selected, &format, &tmpfile))
795 ULOG_INFO("%s() - openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
799 /* update filenames */
800 basename = g_path_get_basename(selected);
802 gtk_label_set_text(GTK_LABEL(data->mainViewData.fileNameEntry), basename);
805 g_free(data->openFileName);
806 data->openFileName = tmpfile;
807 data->file_format = format;
808 //data->filter = format;
809 g_free(data->saveFileName);
810 data->saveFileName = NULL;
811 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
813 len = guessMediaLength(data);
815 setLength(data, len);
817 setLength(data, 0.0);
819 setFormatString(data, data->file_format);
824 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
825 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
834 openURI(gpointer user_data)
838 gchar *selected = NULL;
840 gchar *tmpfile = NULL;
841 gchar *basename = NULL;
845 data = (AppData *) user_data;
847 if (NULL == data->mimeURI)
850 uri = gnome_vfs_uri_new(data->mimeURI);
851 selected = g_strdup(gnome_vfs_uri_get_path(uri));
853 gnome_vfs_uri_unref(uri);
856 g_free(data->mimeURI);
857 data->mimeURI = NULL;
859 /* TODO: the following is duplicated in cbOpen(), move to a tryOpen() function ? */
861 if (NULL == selected)
864 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
866 if (openFile(selected, &format, &tmpfile))
868 ULOG_INFO("%s: openFile() succeeded, format: %d, tmpfile %s", G_STRFUNC, format, tmpfile);
872 /* update filenames */
873 basename = g_path_get_basename(selected);
875 gtk_label_set_text(GTK_LABEL(data->mainViewData.fileNameEntry), basename);
878 g_free(data->openFileName);
879 data->openFileName = tmpfile;
880 data->file_format = format;
881 //data->filter = format;
882 g_free(data->saveFileName);
883 data->saveFileName = NULL;
884 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
886 len = guessMediaLength(data);
888 setLength(data, len);
890 setLength(data, 0.0);
892 setFormatString(data, data->file_format);
897 ULOG_WARN("%s() - openFile() failed", G_STRFUNC);
898 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not open file!"));
906 static void openPlayPipeline( AppData *data )
909 GstFormat fmt = GST_FORMAT_TIME;
913 /* create pipelines */
914 /* check file type */
915 switch (data->file_format)
922 //destroyPipelines(data);
923 //data->filter = data->file_format;
924 createPipeline(data, PIPELINE_PLAY);
928 destroyPipelines(data);
929 //data->filter = data->file_format;
930 createPipeline(data, PIPELINE_PLAY_MP3);
935 ULOG_WARN("%s() - unknown file_format", G_STRFUNC);
936 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Unknown filetype!"));
941 if (!GST_IS_ELEMENT(data->playPipeline))
943 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline!"));
947 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_READY);
948 gst_element_get_state(GST_ELEMENT(data->playPipeline), NULL, NULL, GST_CLOCK_TIME_NONE /* or ns */);
950 /* calculate length */
951 if (gst_element_query_duration (data->playPipeline, &fmt, &len))
955 size = GST_TIME_TO_SECS(len);
956 ULOG_INFO("playSize: len:%lld size:%f", len, size);
957 setLength(data, size);
962 setLength(data, 0.0);
967 /* returns whether the action can proceed or should be aborted */
969 closeFile(AppData *data)
977 note = hildon_note_new_confirmation_add_buttons(GTK_WINDOW(data->mainView), _("Save recording?"),
978 _("Yes"), GTK_RESPONSE_YES,
979 _("No"), GTK_RESPONSE_NO,
982 i = gtk_dialog_run(GTK_DIALOG(note));
983 gtk_widget_destroy(note);
987 case GTK_RESPONSE_CANCEL:
990 case GTK_RESPONSE_NO:
991 if (data->saveFileName)
992 g_unlink(data->saveFileName);
996 case GTK_RESPONSE_YES:
998 cbSaveAs(NULL, data);
1002 ULOG_WARN("%s(): unknown response from dialog: %d", G_STRFUNC, i);
1007 static const gchar *
1008 getFileName(AppData *data)
1011 return gtk_label_get_text(GTK_LABEL(data->mainViewData.fileNameEntry));
1015 static void cbSettings(GtkWidget* widget, AppData *data)
1017 settings_edit( widget, data );
1020 static void cbEmailing(GtkWidget* widget, AppData *data)
1024 GSList *list = NULL;
1027 g_assert(NULL != data);
1029 if (g_file_test(data->openFileName, G_FILE_TEST_EXISTS))
1031 file = file2uri(data->openFileName);
1032 ULOG_INFO("Emailing: %s", file);
1033 list = g_slist_append(list, file);
1034 result = libmodest_dbus_client_compose_mail(data->osso,
1042 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Emailing failed"));
1049 static void cbSaveAs(GtkWidget* widget, AppData *data)
1051 GtkWidget* dialog = NULL;
1052 const gchar *current;
1053 gchar *selected = NULL;
1055 g_assert(NULL != data);
1057 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1059 current = getFileName(data);
1060 if (NULL == current || strcmp(current, RECORDER_FILE_UNTITLED) == 0)
1062 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Nothing to save"));
1067 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new(
1068 GTK_WINDOW(data->mainView),
1069 GTK_FILE_CHOOSER_ACTION_SAVE));
1071 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog),
1072 get_default_dir() );
1075 gtk_widget_show_all(dialog);
1077 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1079 selected = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1082 ULOG_DEBUG("%s() - dialog finished", G_STRFUNC);
1083 gtk_widget_destroy(dialog);
1085 if (NULL == selected)
1088 ULOG_INFO("%s() - selected filename = '%s'", G_STRFUNC, selected);
1090 g_free(data->saveFileName);
1091 data->saveFileName = NULL;
1093 if (saveFile(selected, data->openFileName, data->file_format, &(data->saveFileName)))
1098 g_assert(data->saveFileName);
1100 /* set new title that has the file name */
1101 basename = g_path_get_basename(data->saveFileName);
1102 ULOG_DEBUG("%s() - file '%s' succesfully saved!", G_STRFUNC, data->saveFileName);
1104 /* Houston, we have a kludge:
1105 * for AU files we need to keep the old tmpfile for playback
1106 * for RAW/iLBC files, we can remove the tmpfile and point openFileName to the saved file
1108 ext = getExtension(data->file_format);
1109 if (strcmp(ext, EXTENSION_AU) != 0)
1111 g_free(data->openFileName);
1112 data->openFileName = g_strdup(data->saveFileName);
1115 gtk_label_set_text(GTK_LABEL(data->mainViewData.fileNameEntry),
1123 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Saving file failed!"));
1129 ULOG_DEBUG("%s() - end", G_STRFUNC);
1132 static void cbRec(GtkWidget* widget, GdkEventButton *event, AppData *data)
1134 g_assert(NULL != data);
1136 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1138 if (APPSTATE_RECORDING == getAppState(data))
1140 if (GST_IS_ELEMENT(data->recPipeline))
1142 gst_element_set_state(GST_ELEMENT(data->recPipeline), GST_STATE_PAUSED);
1143 gtk_label_set_text(GTK_LABEL(data->mainViewData.stateEntry),
1144 RECORDER_MSG_PAUSED);
1145 hildon_banner_show_information(GTK_WIDGET(data->mainView), NULL, RECORDER_MSG_PAUSED);
1146 setAppState(data, APPSTATE_PAUSED);
1151 if (APPSTATE_PAUSED == getAppState(data))
1153 if (GST_IS_ELEMENT(data->recPipeline))
1155 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1157 setAppState(data, APPSTATE_RECORDING);
1162 if (APPSTATE_READY != getAppState(data))
1164 ULOG_WARN("%s() - state different than READY -> return", G_STRFUNC);
1165 if (APPSTATE_RECORDING == getAppState(data))
1166 cbStop(widget, NULL,data);
1170 if (!closeFile(data))
1173 /* clear filenames, use tmp file */
1174 g_free(data->openFileName);
1175 data->openFileName = NULL;
1177 g_free(data->saveFileName);
1178 data->saveFileName = NULL;
1180 switch (data->filter)
1183 data->saveFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_FILE);
1184 data->openFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_FILE);
1188 data->saveFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_PCMA_FILE);
1189 data->openFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_PCMA_FILE);
1193 data->saveFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_PCMU_FILE);
1194 data->openFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_PCMU_FILE);
1198 data->saveFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_WAV_FILE);
1199 data->openFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_WAV_FILE);
1204 data->saveFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_ILBC_FILE);
1205 data->openFileName = g_strdup_printf("%s/%s", DEFAULT_TMP_DIR, DEFAULT_TMP_ILBC_FILE);
1209 g_mkdir(DEFAULT_TMP_DIR, 755);
1211 ULOG_INFO("%s() - creating pipelines", G_STRFUNC);
1212 /* start recording */
1213 /* create related pipelines */
1214 if (createPipeline(data, PIPELINE_REC))
1216 ULOG_INFO("%s() - starting recording", G_STRFUNC);
1218 /* start recording */
1220 gst_element_set_state(GST_ELEMENT(data->recPipeline),
1223 /* update display */
1224 basename = g_path_get_basename(data->saveFileName);
1225 gtk_label_set_text(GTK_LABEL(data->mainViewData.fileNameEntry),
1229 setAppState(data, APPSTATE_RECORDING);
1230 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1231 data->file_format = data->filter;
1232 setFormatString(data, data->file_format);
1236 ULOG_ERR("Could not create rec pipeline!");
1237 hildon_banner_show_information(GTK_WIDGET(data->mainView), GTK_STOCK_DIALOG_ERROR, _("Could not create pipeline"));
1238 setAppState(data, APPSTATE_READY);
1241 gtk_widget_set_sensitive(data->buttonPlay, FALSE);
1243 ULOG_DEBUG("%s() - end", G_STRFUNC);
1246 static void cbPlay(GtkWidget* widget, GdkEventButton *event, AppData *data)
1248 const gchar * file = NULL;
1250 g_assert(NULL != data);
1252 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1254 file = getFileName(data);
1255 if (NULL == data->openFileName || NULL == file || strcmp(file, RECORDER_FILE_UNTITLED) == 0)
1257 ULOG_WARN("%s() - nothing to play", G_STRFUNC);
1261 if (APPSTATE_PLAYING == getAppState(data))
1263 if (GST_IS_ELEMENT(data->playPipeline))
1265 gst_element_set_state(GST_ELEMENT(data->playPipeline), GST_STATE_PAUSED);
1266 setAppState(data, APPSTATE_PAUSED);
1271 if (APPSTATE_PAUSED != getAppState(data)) {
1272 openPlayPipeline(data);
1273 setAppState(data, APPSTATE_READY);
1276 if (APPSTATE_READY != getAppState(data) && APPSTATE_PAUSED != getAppState(data))
1278 ULOG_WARN("%s() - state different than PLAYING or READY -> return", G_STRFUNC);
1282 ULOG_INFO("filename %s", file);
1284 if (! GST_IS_ELEMENT(data->playPipeline))
1286 ULOG_WARN("%s() - playPipeline does not exist", G_STRFUNC);
1290 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1293 setAppState(data, APPSTATE_PLAYING);
1295 g_timeout_add(PLAY_UPDATE_INTERVAL, (GSourceFunc)cbCheckPosition, data);
1297 gtk_widget_set_sensitive(data->buttonRec, FALSE);
1299 ULOG_DEBUG("%s() - end", G_STRFUNC);
1302 static void cbStop(GtkWidget* widget, GdkEventButton *event, AppData *data)
1304 g_assert(NULL != data);
1306 ULOG_DEBUG("%s() - begin", G_STRFUNC);
1308 /* check if we are playing/recording */
1310 /* stop playing or recording */
1311 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1312 gtk_widget_set_state(data->buttonRec, GTK_STATE_NORMAL);
1313 gtk_widget_set_sensitive(data->buttonPlay, TRUE);
1314 gtk_widget_set_sensitive(data->buttonRec, TRUE);
1316 /* destroy related pipeline */
1317 switch(getAppState(data))
1319 case APPSTATE_PLAYING:
1320 /* don't destroy the playing pipeline. Instead, set the pipeline to PAUSED */
1321 /* destroyPipeline(data, PIPELINE_PLAY); */
1322 ULOG_INFO("%s() - Setting playPipeline state to PAUSED", G_STRFUNC);
1323 gst_element_set_state(GST_ELEMENT(data->playPipeline),
1325 setAppState(data, APPSTATE_READY);
1327 case APPSTATE_PAUSED:
1328 case APPSTATE_READY:
1329 /* seek to zero, but not for PCM pipeline */
1330 /* if (data->playPipelineType == PIPELINE_PLAY || seekToZero(data, GST_ELEMENT(data->playPipeline))) */
1331 if ( !GST_IS_ELEMENT(data->playPipeline) || seekToZero(data, GST_ELEMENT(data->playPipeline)))
1333 gtk_adjustment_set_value(
1334 GTK_ADJUSTMENT(data->mainViewData.adjustment), 0);
1335 gtk_adjustment_value_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1336 gtk_label_set_text(GTK_LABEL(data->mainViewData.ctime), "00:00");
1337 gtk_label_set_text(GTK_LABEL(data->mainViewData.stateEntry),
1342 case APPSTATE_RECORDING:
1345 gst_element_send_event(GST_ELEMENT(data->recPipeline),
1346 gst_event_new_eos());
1347 gtk_widget_set_sensitive(data->buttonSaveAs, TRUE);
1348 data->saved = FALSE;
1350 len = guessMediaLength(data);
1352 setLength(data, len);
1358 /* seekToZero(data, GST_ELEMENT(data->playPipeline)); */
1359 /* should not come here */
1363 ULOG_DEBUG("%s() - end", G_STRFUNC);
1367 /* ui construction functions */
1369 static void cbItemGroupChanged( gpointer data )
1371 AppData* app = (AppData* ) data;
1372 GValue active ={G_TYPE_INVALID};
1375 g_value_init(&active, G_TYPE_INT);
1377 g_object_get_property(G_OBJECT(app->radio_pcma), "active", &active);
1378 pcma = g_value_get_int(&active);
1379 g_object_get_property(G_OBJECT(app->radio_ilbc), "active", &active);
1380 ilbc = g_value_get_int(&active);
1381 g_object_get_property(G_OBJECT(app->radio_pcm), "active", &active);
1382 pcm = g_value_get_int(&active);
1384 ULOG_INFO("change type pcma=%d ilbc=%d pcm=%d",pcma, ilbc, pcm);
1386 app->filter = FORMAT_PCMA;
1387 else if ( ilbc == 1 )
1388 app->filter = FORMAT_ILBC;
1389 else if ( pcm == 1 )
1390 app->filter = FORMAT_WAV;
1394 ULOG_INFO("filter type=%d", app->filter);
1397 /* Create the menu items needed for the main view */
1398 static void createMenu( AppData *data )
1400 HildonAppMenu *menu;
1401 GtkWidget *button_new;
1402 GtkWidget *button_open;
1403 GtkWidget *button_save;
1404 GtkWidget *button_email;
1406 menu = HILDON_APP_MENU( hildon_app_menu_new() );
1407 button_new = hildon_gtk_button_new(HILDON_SIZE_AUTO);
1408 gtk_button_set_label( GTK_BUTTON(button_new), "New");
1409 button_open = hildon_gtk_button_new(HILDON_SIZE_AUTO);
1410 gtk_button_set_label( GTK_BUTTON(button_open), "Open");
1411 button_save = hildon_gtk_button_new(HILDON_SIZE_AUTO);
1412 data->buttonSaveAs = button_save;
1413 gtk_widget_set_sensitive(data->buttonSaveAs, FALSE);
1414 gtk_button_set_label( GTK_BUTTON(button_save), "Save");
1415 button_email = hildon_gtk_button_new(HILDON_SIZE_AUTO);
1416 gtk_button_set_label( GTK_BUTTON(button_email), "Send via email");
1418 hildon_app_menu_append( menu, GTK_BUTTON(button_new));
1419 hildon_app_menu_append( menu, GTK_BUTTON(button_open));
1420 hildon_app_menu_append( menu, GTK_BUTTON(button_save));
1421 hildon_app_menu_append( menu, GTK_BUTTON(button_email));
1422 g_signal_connect(G_OBJECT(button_new), "clicked",
1425 g_signal_connect(G_OBJECT(button_open), "clicked",
1428 g_signal_connect(G_OBJECT(button_save), "clicked",
1429 G_CALLBACK(cbSaveAs),
1431 g_signal_connect( G_OBJECT( button_email ), "clicked",
1432 GTK_SIGNAL_FUNC (cbEmailing), data);
1434 gtk_widget_show_all( GTK_WIDGET(menu));
1436 hildon_window_set_app_menu(HILDON_WINDOW(data->mainView), menu);
1438 data->filter = get_default_filter();
1440 setFormatString(data, data->filter);
1445 cbScaleRelease(GtkWidget *widget, GdkEventButton *ev, gpointer data)
1447 AppData* app = (AppData* ) data;
1449 if (getAppState(app) == APPSTATE_RECORDING || NULL == app->playPipeline)
1452 seekToTime(app->playPipeline, gtk_adjustment_get_value(GTK_ADJUSTMENT(app->mainViewData.adjustment)));
1459 evKeypress(GtkWidget *widget, GdkEventKey *ev, AppData *appdata)
1465 cbRec(widget, NULL, appdata);
1468 cbPlay(widget, NULL, appdata);
1471 cbStop(widget, NULL, appdata);
1481 gboolean maemo_recorder_ui_new(AppData *data)
1483 HildonProgram *app = NULL;
1484 HildonWindow *window = NULL;
1485 GtkWidget *hbox = NULL;
1486 GtkWidget *ctime = NULL;
1487 GtkWidget *etime = NULL;
1488 GtkWidget *filename = NULL;
1489 GtkWidget *format = NULL;
1490 GtkWidget *state = NULL;
1491 GtkWidget *table = NULL;
1492 GtkWidget *scale = NULL;
1493 GtkObject *adjustment = NULL;
1495 GtkWidget *rec = NULL;
1496 GtkWidget *play = NULL;
1497 GtkWidget *stop = NULL;
1498 GtkWidget *recimage = NULL;
1499 GtkWidget *playimage = NULL;
1500 GtkWidget *stopimage = NULL;
1502 g_assert(NULL != data);
1504 app = HILDON_PROGRAM(hildon_program_get_instance());
1505 g_set_application_name(RECORDER_APP_TITLE);
1508 window = HILDON_WINDOW(hildon_window_new());
1510 hildon_program_add_window(app, window);
1512 /* content for main view */
1514 /* create hbox to divide control area */
1515 hbox = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
1517 /* create toolbar */
1519 /* create table for labels */
1520 table = gtk_table_new (6, 6, TRUE);
1521 gtk_table_set_homogeneous(GTK_TABLE(table), TRUE);
1523 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
1524 gtk_table_set_col_spacings (GTK_TABLE (table), HILDON_MARGIN_TRIPLE);
1526 filename = gtk_label_new(_(RECORDER_FILE_UNTITLED));
1527 format = gtk_label_new(RECORDER_FMT_STRING_NONE);
1528 state = gtk_label_new("");
1529 adjustment = gtk_adjustment_new (0.00,
1536 ctime = gtk_label_new("00:00");
1537 etime = gtk_label_new("00:00");
1538 scale = gtk_hscale_new(GTK_ADJUSTMENT(adjustment));
1539 gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
1540 gtk_box_pack_start(GTK_BOX(hbox), ctime, FALSE, FALSE, HILDON_MARGIN_DOUBLE);
1541 gtk_box_pack_end(GTK_BOX(hbox), etime, FALSE, FALSE, HILDON_MARGIN_DOUBLE);
1542 gtk_box_pack_end(GTK_BOX(hbox), scale, TRUE, TRUE, HILDON_MARGIN_DOUBLE);
1543 gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
1545 gtk_table_attach_defaults(GTK_TABLE(table), filename,
1547 gtk_table_attach_defaults(GTK_TABLE(table), format,
1549 gtk_table_attach_defaults(GTK_TABLE(table), state,
1551 gtk_table_attach_defaults(GTK_TABLE(table), hbox,
1555 recimage = gtk_image_new_from_file(REC_ICON);
1556 rec = gtk_event_box_new();
1557 data->buttonRec = GTK_WIDGET(rec);
1558 gtk_container_add(GTK_CONTAINER(rec), recimage);
1559 playimage = gtk_image_new_from_file(PLAY_ICON);
1560 play = gtk_event_box_new();
1561 data->buttonPlay = GTK_WIDGET(play);
1562 gtk_container_add(GTK_CONTAINER(play), playimage);
1563 stopimage = gtk_image_new_from_file(STOP_ICON);
1564 stop = gtk_event_box_new();
1565 gtk_container_add(GTK_CONTAINER(stop), stopimage);
1567 gtk_table_attach_defaults(GTK_TABLE(table), rec,
1569 gtk_table_attach_defaults(GTK_TABLE(table), play,
1571 gtk_table_attach_defaults(GTK_TABLE(table), stop,
1575 /* connect signals */
1576 g_signal_connect(G_OBJECT(scale), "button-release-event", G_CALLBACK(cbScaleRelease), data);
1577 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(cbDestroy), data);
1578 g_signal_connect(G_OBJECT(window), "key-press-event",
1579 G_CALLBACK(evKeypress), data);
1581 g_signal_connect(G_OBJECT(rec), "button-release-event",
1584 g_signal_connect(G_OBJECT(play), "button-release-event",
1587 g_signal_connect(G_OBJECT(stop), "button-release-event",
1592 /* packing the view */
1593 gtk_container_add(GTK_CONTAINER(window), table);
1595 /* store needed widgets */
1597 data->mainView = window;
1598 data->mainViewData.fileNameEntry = GTK_WIDGET(filename);
1599 data->mainViewData.formatEntry = GTK_WIDGET(format);
1600 data->mainViewData.lengthEntry = GTK_WIDGET(etime);
1601 data->mainViewData.ctime = GTK_WIDGET(ctime);
1602 data->mainViewData.stateEntry = GTK_WIDGET(state);
1603 data->mainViewData.adjustment = GTK_OBJECT(adjustment);
1606 gtk_widget_show_all(GTK_WIDGET(window));
1614 maemo_recorder_mime_open(gpointer user_data, gint argc, gchar **argv)
1618 ULOG_DEBUG("%s with %d arguments", __FUNCTION__, argc);
1623 g_assert(user_data);
1624 data = (AppData *) user_data;
1626 if (argv[0] != NULL)
1628 ULOG_DEBUG("request to open %s", argv[0]);
1629 g_free(data->mimeURI);
1630 data->mimeURI = g_strdup(argv[0]);
1631 g_idle_add(openURI, (gpointer) data);
1632 gtk_window_present(GTK_WINDOW(data->mainView));
1636 static void seekToTime(GstElement *pipeline, gdouble secs)
1638 g_assert(NULL != pipeline);
1639 ULOG_DEBUG("Seeking to: %.2f", secs);
1641 /* time must be nanoseconds */
1642 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1643 GST_SEEK_TYPE_SET, (gint64) (secs * GST_SECOND),
1644 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1646 ULOG_WARN("seekToTime failed!");
1649 ULOG_DEBUG("seekToTime succeeded");
1652 static gboolean seekToZero(AppData *data, GstElement *pipeline)
1655 g_assert(NULL != pipeline);
1656 ULOG_DEBUG("Seeking to zero");
1658 /* time must be nanoseconds */
1659 if (!gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1660 GST_SEEK_TYPE_SET, (gint64) 0,
1661 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
1663 ULOG_ERR("seekToZero failed! Trying to destroy and re-create pipeline");
1664 plType = data->playPipelineType;
1666 /* gst_element_set_state(pipeline, GST_STATE_READY); */
1667 destroyPipeline(data, plType);
1668 return createPipeline(data, plType);
1671 ULOG_DEBUG("seekToZero succeeded");
1676 setFormatString(AppData *data, AudioFormat afmt)
1681 /* these are pretty much always the same */
1683 gint rate = DEFAULT_RATE; /* 8000 */
1687 g_assert(GTK_IS_LABEL(data->mainViewData.formatEntry));
1692 format = FORMAT_NAME_PCMA;
1695 format = FORMAT_NAME_PCMU;
1698 format = FORMAT_NAME_ILBC;
1701 /* TODO: we can play wavs with many sampling rates, 2 channels */
1702 /* we really should migrate to the better format spec */
1704 format = FORMAT_NAME_WAV;
1708 format = FORMAT_NAME_PCM;
1712 gtk_label_set_text(GTK_LABEL(data->mainViewData.formatEntry), RECORDER_FMT_STRING_NONE);
1716 str = g_strdup_printf("%s, %d %s, %d kHz, %d %s", format, channels, _("ch"), rate/1000, bits, _("bits"));
1717 gtk_label_set_text(GTK_LABEL(data->mainViewData.formatEntry), str);
1721 static void setLength(AppData *data, gdouble secs)
1731 g_object_set(G_OBJECT(data->mainViewData.adjustment),
1734 gtk_adjustment_changed(GTK_ADJUSTMENT(data->mainViewData.adjustment));
1740 secs -= mins * 60.0;
1743 tmp = g_strdup_printf("%02u:%02d", mins, (int)secs);
1746 ULOG_INFO("Setting length to %s", tmp);
1748 gtk_label_set_text(GTK_LABEL(data->mainViewData.lengthEntry),
1753 static gdouble guessMediaLength(AppData *data)
1755 GnomeVFSFileSize size = 0;
1756 gdouble bitrate = 0.0;
1759 if (data->openFileName)
1760 size = getFileLength(data->openFileName);
1767 ULOG_DEBUG("file size: %llu bytes", size);
1769 switch (data->file_format)
1772 bitrate = ILBC_BITRATE_30;
1777 bitrate = PCMA_BITRATE;
1787 len = (((gdouble) size) * 8.0) / (bitrate);
1788 ULOG_DEBUG("guessed media length: %.2f secs", len);
1793 static GstCaps *createCapsFilter(AudioFormat format)
1798 return gst_caps_new_simple(
1800 "rate", G_TYPE_INT, ILBC_RATE,
1801 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1802 "mode", G_TYPE_INT, 30, /* 30 ms frames */
1805 return gst_caps_new_simple(
1807 "rate", G_TYPE_INT, DEFAULT_RATE,
1808 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1811 return gst_caps_new_simple(
1813 "rate", G_TYPE_INT, DEFAULT_RATE,
1814 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1818 return gst_caps_new_simple(
1820 "rate", G_TYPE_INT, PCM_RATE,
1821 "signed", G_TYPE_BOOLEAN, TRUE,
1822 "channels", G_TYPE_INT, DEFAULT_CHANNELS,
1823 "endianness", G_TYPE_INT, PCM_ENDIANNESS,
1824 "width", G_TYPE_INT, PCM_WIDTH,
1825 "depth", G_TYPE_INT, PCM_DEPTH,
1828 ULOG_WARN("%s(): creating ANY caps", G_STRFUNC);
1829 return gst_caps_new_any();
1833 static gboolean cbStopPlayback(AppData *data)
1835 ULOG_INFO("Stopping playback");
1837 g_assert(data != NULL);
1838 destroyPipelines(data);
1839 setAppState(data, APPSTATE_READY);
1840 gtk_widget_set_state(data->buttonPlay, GTK_STATE_NORMAL);
1845 static gboolean cbUpdateRecLength(AppData *data)
1851 data->rectime += REC_UPDATE_INTERVAL/1000.0;
1853 mins = data->rectime / 60;
1854 secs = data->rectime - (mins * 60.0);
1855 tmp = g_strdup_printf("%02u:%02d", mins, (int)secs);
1857 gtk_label_set_text(GTK_LABEL(data->mainViewData.lengthEntry),
1861 if (getAppState(data) == APPSTATE_RECORDING)
1864 data->recUpdateId = 0;