2c9ed715bc4403a97e541cfe7b6ecf64b2460949
[oweals/gnunet.git] / src / conversation / gnunet-conversation-test.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file conversation/gnunet-conversation-test.c
21  * @brief tool to test speaker and microphone (for end users!)
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "gnunet_speaker_lib.h"
27 #include "gnunet_microphone_lib.h"
28
29 /**
30  * How long do we record before we replay?
31  */
32 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
33
34
35 /**
36  * A recording we made.
37  */
38 struct Recording
39 {
40   /**
41    * Kept in a DLL.
42    */
43   struct Recording *next;
44
45   /**
46    * Kept in a DLL.
47    */
48   struct Recording *prev;
49
50   /**
51    * Number of bytes that follow.
52    */
53   size_t size;
54 };
55
56
57 /**
58  * Final status code.
59  */
60 static int ret;
61
62 /**
63  * Handle to the microphone.
64  */
65 static struct GNUNET_MICROPHONE_Handle *microphone;
66
67 /**
68  * Handle to the speaker.
69  */
70 static struct GNUNET_SPEAKER_Handle *speaker;
71
72 /**
73  * Task scheduled to switch from recording to playback.
74  */
75 static struct GNUNET_SCHEDULER_Task * switch_task;
76
77 /**
78  * The shutdown task.
79  */
80 static struct GNUNET_SCHEDULER_Task * st;
81
82 /**
83  * Head of DLL with recorded frames.
84  */
85 static struct Recording *rec_head;
86
87 /**
88  * Tail of DLL with recorded frames.
89  */
90 static struct Recording *rec_tail;
91
92
93 /**
94  * Terminate test.
95  *
96  * @param cls NULL
97  */
98 static void
99 do_shutdown (void *cls)
100 {
101   struct Recording *rec;
102
103   (void) cls;
104   if (NULL != switch_task)
105     GNUNET_SCHEDULER_cancel (switch_task);
106   if (NULL != microphone)
107     GNUNET_MICROPHONE_destroy (microphone);
108   if (NULL != speaker)
109     GNUNET_SPEAKER_destroy (speaker);
110   while (NULL != (rec = rec_head))
111   {
112     GNUNET_CONTAINER_DLL_remove (rec_head,
113                                  rec_tail,
114                                  rec);
115     GNUNET_free (rec);
116   }
117   fprintf (stderr,
118            _("\nEnd of transmission.  Have a GNU day.\n"));
119 }
120
121
122 /**
123  * Terminate recording process and switch to playback.
124  *
125  * @param cls NULL
126  */
127 static void
128 switch_to_speaker (void *cls)
129 {
130   (void) cls;
131   switch_task = NULL;
132   microphone->disable_microphone (microphone->cls);
133   if (GNUNET_OK !=
134       speaker->enable_speaker (speaker->cls))
135   {
136     fprintf (stderr,
137              "Failed to enable microphone\n");
138     ret = 1;
139     GNUNET_SCHEDULER_shutdown ();
140     return;
141   }
142   fprintf (stderr,
143            _("\nWe are now playing your recording back.  If you can hear it, your audio settings are working..."));
144   for (struct Recording *rec=rec_head; NULL != rec; rec = rec->next)
145   {
146     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
147                 "Replaying %u bytes\n",
148                 (unsigned int) rec->size);
149     speaker->play (speaker->cls,
150                    rec->size,
151                    &rec[1]);
152   }
153   GNUNET_SCHEDULER_cancel (st);
154   st = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
155                                      &do_shutdown,
156                                      NULL);
157 }
158
159
160 /**
161  * Process recorded audio data.
162  *
163  * @param cls clsoure
164  * @param data_size number of bytes in @a data
165  * @param data audio data to play
166  */
167 static void
168 record (void *cls,
169         size_t data_size,
170         const void *data)
171 {
172   struct Recording *rec;
173
174   (void) cls;
175   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
176               "Recorded %u bytes\n",
177               (unsigned int) data_size);
178   rec = GNUNET_malloc (sizeof (struct Recording) + data_size);
179   rec->size = data_size;
180   GNUNET_memcpy (&rec[1], data, data_size);
181   GNUNET_CONTAINER_DLL_insert_tail (rec_head,
182                                     rec_tail,
183                                     rec);
184 }
185
186
187 /**
188  * Main function that will be run by the scheduler.
189  *
190  * @param cls closure
191  * @param args remaining command-line arguments
192  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
193  * @param cfg configuration
194  */
195 static void
196 run (void *cls,
197      char *const *args,
198      const char *cfgfile,
199      const struct GNUNET_CONFIGURATION_Handle *cfg)
200 {
201   (void) cls;
202   (void) args;
203   (void) cfgfile;
204   microphone = GNUNET_MICROPHONE_create_from_hardware (cfg);
205   GNUNET_assert (NULL != microphone);
206   speaker = GNUNET_SPEAKER_create_from_hardware (cfg);
207   GNUNET_assert (NULL != speaker);
208   switch_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
209                                               &switch_to_speaker,
210                                               NULL);
211   st = GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
212                                       NULL);
213   fprintf (stderr,
214            _("We will now be recording you for %s. After that time, the recording will be played back to you..."),
215            GNUNET_STRINGS_relative_time_to_string (TIMEOUT, GNUNET_YES));
216   if (GNUNET_OK !=
217       microphone->enable_microphone (microphone->cls,
218                                      &record, NULL))
219   {
220     fprintf (stderr,
221              "Failed to enable microphone\n");
222     ret = 1;
223     GNUNET_SCHEDULER_shutdown ();
224     return;
225   }
226 }
227
228
229 /**
230  * The main function of our code to test microphone and speaker.
231  *
232  * @param argc number of arguments from the command line
233  * @param argv command line arguments
234  * @return 0 ok, 1 on error
235  */
236 int
237 main (int argc,
238       char *const *argv)
239 {
240   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
241     GNUNET_GETOPT_OPTION_END
242   };
243   
244   if (GNUNET_OK !=
245       GNUNET_STRINGS_get_utf8_args (argc, argv,
246                                     &argc, &argv))
247     return 2;
248
249   ret = (GNUNET_OK ==
250          GNUNET_PROGRAM_run (argc, argv,
251                              "gnunet-conversation-test",
252                              gettext_noop ("help text"),
253                              options,
254                              &run,
255                              NULL)) ? ret : 1;
256   GNUNET_free ((void*) argv);
257   return ret;
258 }
259
260 /* end of gnunet-conversation-test.c */