]> err.no Git - mapper/blob - src/audio-note.c
Set caps so we don't record @ 32-bit stereo 44100. Skip on tablets as they default...
[mapper] / src / audio-note.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2007 Kaj-Michael Lang
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 /*
22  * Quick record audio notes on the road.
23  */
24
25 #include "config.h"
26 #include <glib.h>
27 #include <gst/gst.h>
28 #include <gtk/gtk.h>
29
30 #include "ui-common.h"
31 #include "audio.h"
32 #include "audio-note.h"
33
34 static note_pipeline note_play;
35 static note_pipeline note_record;
36 static GstBus *bus;
37 static gchar *cfile=NULL;
38
39 static gboolean
40 audio_note_record_cb(GtkWidget *widget, gpointer data)
41 {
42 const gchar *basedir;
43 gchar buffer[128];
44 audio_note_ui *ui=(audio_note_ui *)data;
45 GDate *gd;
46 time_t t;
47 struct tm *tmp;
48
49 /* XXX: Make this a configuration option */
50 #ifdef WITH_DEVICE_770
51 basedir="/media/mmc1/MapperAudioNotes";
52 if (g_mkdir_with_parents(basedir, 0775)==-1) {
53         MACRO_BANNER_SHOW_INFO(_window, _("Failed to create directory for sound files!"));
54         return TRUE;
55 }
56 #else
57 basedir=g_get_home_dir();
58 #endif
59
60 t=time(NULL);
61 tmp=localtime(&t);
62 if (tmp == NULL) {
63         MACRO_BANNER_SHOW_INFO(_window, _("Failed to get timestamp for file!"));
64         return TRUE;
65 }
66 strftime(buffer, sizeof(buffer), "%Y-%m-%d-%H:%M:%S", tmp);
67
68 if (cfile)
69         g_free(cfile);
70
71 cfile=g_strdup_printf("%s/an-%s.wav", basedir, buffer);
72
73 audio_note_record(cfile);
74
75 MACRO_BANNER_SHOW_INFO(_window, _("Recording..."));
76
77 return TRUE;
78 }
79
80 static gboolean
81 audio_note_play_cb(GtkWidget *widget, gpointer data)
82 {
83 audio_note_ui *ui=(audio_note_ui *)data;
84
85 audio_note_play(cfile);
86 MACRO_BANNER_SHOW_INFO(_window, _("Playing..."));
87 return TRUE;
88 }
89
90 static gboolean
91 audio_note_stop_cb(GtkWidget *widget, gpointer data)
92 {
93 if (audio_note_stop()==TRUE)
94         MACRO_BANNER_SHOW_INFO(_window, _("Stopped..."));
95 return TRUE;
96 }
97
98 audio_note_ui *
99 audio_note_new(void)
100 {
101 audio_note_ui *ui;
102 ui=g_slice_new(audio_note_ui);
103 ui->vbox=gtk_vbox_new(FALSE, 0);
104 ui->lbl_time=gtk_label_new("");
105 ui->btn_record=gtk_button_new_from_stock(GTK_STOCK_MEDIA_RECORD);
106 ui->btn_play=gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
107 ui->btn_stop=gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
108
109 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->lbl_time, TRUE, TRUE, 0);
110 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_record, TRUE, TRUE, 0);
111 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_play, TRUE, TRUE, 0);
112 gtk_box_pack_start(GTK_BOX(ui->vbox), ui->btn_stop, TRUE, TRUE, 0);
113
114 ui->note_play=&note_play;
115 ui->note_record=&note_record;
116
117 g_signal_connect(G_OBJECT(ui->btn_record), "clicked", G_CALLBACK(audio_note_record_cb), ui);
118 g_signal_connect(G_OBJECT(ui->btn_play), "clicked", G_CALLBACK(audio_note_play_cb), ui);
119 g_signal_connect(G_OBJECT(ui->btn_stop), "clicked", G_CALLBACK(audio_note_stop_cb), ui);
120
121 return ui;
122 }
123
124 static gboolean
125 audio_note_bus_cb(GstBus *bus, GstMessage *msg, gpointer data)
126 {
127 gchar *debug;
128 GError *err;
129 note_pipeline *np=(note_pipeline *)data;
130
131 switch (GST_MESSAGE_TYPE (msg)) {
132         case GST_MESSAGE_EOS:
133                 np->active=FALSE;
134         g_debug("EOS\n");
135         break;
136         case GST_MESSAGE_ERROR:
137                 gst_message_parse_error (msg, &err, &debug);
138                 g_debug("Error: %s", err->message);
139                 g_free(debug);
140                 g_error_free(err);
141                 np->active=FALSE;
142         break;
143         case GST_MESSAGE_STATE_CHANGED:
144                 g_debug("GST: %s", gst_message_type_get_name(GST_MESSAGE_TYPE(msg)));
145         break;
146     default:
147                 g_debug("GST: %s", gst_message_type_get_name(GST_MESSAGE_TYPE(msg)));
148         break;
149         }
150 return TRUE;
151 }
152
153 static gboolean
154 audio_create_pipeline(note_pipeline *np, gboolean rec)
155 {
156 np->pipeline=gst_pipeline_new("pipeline");
157 bus=gst_pipeline_get_bus(GST_PIPELINE(np->pipeline));
158 gst_bus_add_watch(bus, audio_note_bus_cb, np);
159
160 if (rec==TRUE) {
161         g_debug("GST: Creating record pipeline");
162         np->src=gst_element_factory_make(AUDIO_SRC, "source");
163         np->filter=gst_element_factory_make("wavenc", "filter");
164         np->sink=gst_element_factory_make("filesink", "sink");
165
166         gst_bin_add_many(GST_BIN(np->pipeline), np->src, np->filter, np->sink, NULL);
167
168 #ifndef WITH_DEVICE_770
169         /* Don't waste space with some hifi format */
170         np->srccaps=gst_caps_new_simple ("audio/x-raw-int",
171                         "depth", G_TYPE_INT, 16,
172                         "signed", G_TYPE_BOOLEAN, TRUE, 
173                         "width", G_TYPE_INT, 16,
174                         "rate", G_TYPE_INT, 11025,
175                         "channels", G_TYPE_INT, 1,
176                         NULL);
177         if (!gst_element_link_filtered(np->src, np->filter, np->srccaps))
178                 g_printerr("Failed to set caps for source\n");
179         else
180                 gst_element_link(np->src, np->filter);
181         gst_caps_unref(np->srccaps);
182 #else
183         gst_element_link(np->src, np->filter);  
184 #endif
185         gst_element_link(np->filter, np->sink);
186
187 } else {
188         g_debug("GST: Creating playback pipeline");
189         np->src=gst_element_factory_make("filesrc", "source");
190         np->filter=gst_element_factory_make("wavparse", "filter");
191         np->sink=gst_element_factory_make(AUDIO_SINK, "sink");
192         gst_bin_add_many(GST_BIN(np->pipeline), np->src, np->filter, np->sink, NULL);
193         if (!gst_element_link_many(np->src, np->filter, np->sink, NULL))
194                 g_printerr("Failed to link play pipeline\n");
195 }
196 np->rec=rec;
197 np->active=FALSE;
198 return TRUE;
199 }
200
201 /**
202  * Set the given elements (filesrc or filesink) file location
203  */
204 static void
205 audio_set_filename(GstElement *e, gchar *file)
206 {
207 g_object_set(G_OBJECT(e), "location", file, NULL);
208 }
209
210 /**
211  * Play given audio note file
212  */
213 gboolean
214 audio_note_play(gchar *file)
215 {
216 if (note_play.active==TRUE)
217         return TRUE;
218 audio_set_filename(note_play.src, file);
219 if (gst_element_set_state(note_play.pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
220         g_printerr("Failed to play file %s\n", file);
221         note_play.active=FALSE;
222         return FALSE;
223 }
224 g_debug("Playing");
225 note_play.active=TRUE;
226 return TRUE;
227 }
228
229 /**
230  * Record to given file
231  */
232 gboolean
233 audio_note_record(gchar *file)
234 {
235 if (note_record.active==TRUE)
236         return TRUE;
237 audio_set_filename(note_record.sink, file);
238 if (gst_element_set_state(note_record.pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
239         g_printerr("Failed to record to file %s\n", file);
240         note_record.active=FALSE;
241         return FALSE;
242 }
243 g_debug("Recording");
244 note_record.active=TRUE;
245 return TRUE;
246 }
247
248 gboolean
249 audio_note_stop()
250 {
251 GstState current;
252 GstState pending;
253
254 gst_element_get_state(note_record.pipeline, &current, &pending, GST_CLOCK_TIME_NONE);
255 if (current==GST_STATE_PLAYING) {
256         gst_element_set_state(note_record.pipeline, GST_STATE_PAUSED);
257         note_record.active=FALSE;
258         return TRUE;
259 }
260
261 gst_element_get_state(note_play.pipeline, &current, &pending, GST_CLOCK_TIME_NONE);
262 if (current==GST_STATE_PLAYING) {
263         gst_element_set_state(note_play.pipeline, GST_STATE_PAUSED);
264         note_play.active=FALSE;
265         return TRUE;
266 }
267
268 return FALSE;
269 }
270
271 /**
272  * Init gst pipelines for note play and record
273  */
274 gboolean
275 audio_note_init(void)
276 {
277 audio_create_pipeline(&note_play, FALSE);
278 audio_create_pipeline(&note_record, TRUE);
279 return TRUE;
280 }
281
282 void
283 audio_note_deinit(void)
284 {
285 gst_element_set_state(note_play.pipeline, GST_STATE_NULL);
286 gst_object_unref(note_play.pipeline);
287
288 gst_element_set_state(note_record.pipeline, GST_STATE_NULL);
289 gst_object_unref(note_record.pipeline);
290 }
291