~jbicha/hud/build-depend-on-valac-not-gir

« back to all changes in this revision

Viewing changes to src/hudjulius.c

  • Committer: Tarmac
  • Author(s): Ted Gould, Pete Woods, Antti Kaijanmäki, Ted Gould, Albert Astals, Ryan Lortie, Łukasz 'sil2100' Zemczak, Albert Astals Cid, Mathieu Trudel-Lapierre, Kaleo, Tarmac, Ricardo Salveti de Araujo, Michael Terry, Automatic PS uploader
  • Date: 2013-04-10 16:04:51 UTC
  • mfrom: (227.3.148 phablet)
  • Revision ID: tarmac-20130410160451-o3owpv3zaxulm5of
HUD 2.0 Merge.

Approved by PS Jenkins bot, Mathieu Trudel-Lapierre.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2012 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 3, as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
10
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
11
 * PURPOSE.  See the GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along
 
14
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 */
 
16
 
 
17
#define _POSIX_SOURCE 1
 
18
#define G_LOG_DOMAIN "hudjulius"
 
19
 
 
20
#include "hudjulius.h"
 
21
#include "hudsource.h"
 
22
#include "pronounce-dict.h"
 
23
#include "hud-query-iface.h"
 
24
 
 
25
#include <glib/gstdio.h>
 
26
#include <gio/gio.h>
 
27
#include <signal.h>
 
28
 
 
29
struct _HudJulius
 
30
{
 
31
  GObject parent_instance;
 
32
 
 
33
  HudQueryIfaceComCanonicalHudQuery * skel;
 
34
 
 
35
  GRegex * alphanumeric_regex;
 
36
 
 
37
  gchar **query;
 
38
 
 
39
  gboolean listen_emitted;
 
40
 
 
41
  gboolean heard_something_emitted;
 
42
 
 
43
  GMainLoop *mainloop;
 
44
 
 
45
  guint timeout_source;
 
46
 
 
47
  guint watch_source;
 
48
 
 
49
  GError **error;
 
50
};
 
51
 
 
52
static GQuark
 
53
hud_julius_error_quark(void)
 
54
{
 
55
  static GQuark quark = 0;
 
56
  if (quark == 0)
 
57
    quark = g_quark_from_static_string ("hud-julius-error-quark");
 
58
  return quark;
 
59
}
 
60
 
 
61
static GRegex *
 
62
hud_julius_alphanumeric_regex_new (void)
 
63
{
 
64
  GRegex *alphanumeric_regex = NULL;
 
65
 
 
66
  GError *error = NULL;
 
67
  alphanumeric_regex = g_regex_new("…|\\.\\.\\.", 0, 0, &error);
 
68
  if (alphanumeric_regex == NULL) {
 
69
    g_error("Compiling regex failed: [%s]", error->message);
 
70
    g_error_free(error);
 
71
  }
 
72
 
 
73
  return alphanumeric_regex;
 
74
}
 
75
 
 
76
static void rm_rf(const gchar *path);
 
77
 
 
78
typedef GObjectClass HudJuliusClass;
 
79
 
 
80
static void hud_julius_finalize (GObject *object);
 
81
 
 
82
static gboolean hud_julius_voice_query (HudVoice *self, HudSource *source,
 
83
    gchar **result, GError **error);
 
84
 
 
85
static void hud_julius_iface_init (HudVoiceInterface *iface);
 
86
 
 
87
G_DEFINE_TYPE_WITH_CODE (HudJulius, hud_julius, G_TYPE_OBJECT,
 
88
                         G_IMPLEMENT_INTERFACE (HUD_TYPE_VOICE, hud_julius_iface_init))
 
89
 
 
90
static void hud_julius_iface_init (HudVoiceInterface *iface)
 
91
{
 
92
  iface->query = hud_julius_voice_query;
 
93
}
 
94
 
 
95
static void
 
96
hud_julius_class_init (HudJuliusClass *klass)
 
97
{
 
98
  klass->finalize = hud_julius_finalize;
 
99
}
 
100
 
 
101
static void
 
102
hud_julius_init (HudJulius *self)
 
103
{
 
104
  self->alphanumeric_regex = hud_julius_alphanumeric_regex_new();
 
105
}
 
106
 
 
107
static void
 
108
hud_julius_finalize (GObject *object)
 
109
{
 
110
  HudJulius *self = HUD_JULIUS (object);
 
111
 
 
112
  g_clear_object(&self->skel);
 
113
  g_clear_pointer(&self->alphanumeric_regex, g_regex_unref);
 
114
 
 
115
  G_OBJECT_CLASS (hud_julius_parent_class)
 
116
    ->finalize (object);
 
117
}
 
118
 
 
119
static gchar *
 
120
hud_julius_get_daemon_path ()
 
121
{
 
122
  return g_build_filename (LIBEXECDIR, "hud", "hud-julius-listen", NULL );
 
123
}
 
124
 
 
125
static gboolean
 
126
timeout_quit_func (gpointer user_data)
 
127
{
 
128
  g_assert(HUD_IS_JULIUS(user_data));
 
129
 
 
130
  HudJulius *self = HUD_JULIUS(user_data);
 
131
  g_debug("Query timeout");
 
132
  *self->query = g_strdup("");
 
133
  g_source_remove(self->watch_source);
 
134
  g_main_loop_quit(self->mainloop);
 
135
  return FALSE;
 
136
}
 
137
 
 
138
static gboolean
 
139
watch_function (GIOChannel *channel, GIOCondition condition,
 
140
    gpointer user_data)
 
141
{
 
142
  g_assert(HUD_IS_JULIUS(user_data));
 
143
 
 
144
  HudJulius *self = HUD_JULIUS(user_data);
 
145
 
 
146
  if ((condition & G_IO_IN) != 0)
 
147
  {
 
148
    GString *line = g_string_sized_new (100);
 
149
    GIOStatus status;
 
150
 
 
151
    do
 
152
    {
 
153
      do
 
154
      {
 
155
        *self->error = NULL;
 
156
        status = g_io_channel_read_line_string (channel, line, NULL,
 
157
            self->error);
 
158
      }
 
159
      while (status == G_IO_STATUS_AGAIN);
 
160
 
 
161
      if (status != G_IO_STATUS_NORMAL)
 
162
      {
 
163
        if (*self->error)
 
164
        {
 
165
          g_warning("IO ERROR(): %s", (*self->error)->message);
 
166
          return FALSE;
 
167
        }
 
168
      }
 
169
 
 
170
      if (g_str_has_prefix (line->str, "<voice-query-listening/>"))
 
171
      {
 
172
        if (!self->listen_emitted)
 
173
        {
 
174
          self->listen_emitted = TRUE;
 
175
          hud_query_iface_com_canonical_hud_query_emit_voice_query_listening (
 
176
              HUD_QUERY_IFACE_COM_CANONICAL_HUD_QUERY (self->skel) );
 
177
          g_debug("<<< please speak >>>");
 
178
        }
 
179
      }
 
180
      else if (g_str_has_prefix (line->str, "<voice-query-heard-something/>"))
 
181
      {
 
182
        if (!self->heard_something_emitted)
 
183
        {
 
184
          self->heard_something_emitted = TRUE;
 
185
          hud_query_iface_com_canonical_hud_query_emit_voice_query_heard_something (
 
186
              HUD_QUERY_IFACE_COM_CANONICAL_HUD_QUERY (self->skel) );
 
187
          g_debug("<<< speech input >>>");
 
188
        }
 
189
      }
 
190
      else if (g_str_has_prefix (line->str, "<voice-query-finished>"))
 
191
      {
 
192
        gchar *tmp = g_string_free (line, FALSE);
 
193
        GRegex *regex = g_regex_new("<voice-query-finished>|</voice-query-finished>", 0, 0, NULL);
 
194
        *self->query = g_regex_replace_literal(regex, g_strstrip(tmp), -1, 0, "", 0, NULL);
 
195
        g_regex_unref(regex);
 
196
        g_free(tmp);
 
197
        g_source_remove(self->timeout_source);
 
198
        g_main_loop_quit(self->mainloop);
 
199
        return FALSE;
 
200
      }
 
201
    }
 
202
    while (g_io_channel_get_buffer_condition (channel) == G_IO_IN);
 
203
    g_string_free (line, TRUE);
 
204
 
 
205
  }
 
206
 
 
207
  if ((condition & G_IO_HUP) != 0)
 
208
  {
 
209
    g_io_channel_shutdown (channel, TRUE, NULL );
 
210
    *self->query = NULL;
 
211
    *self->error = g_error_new_literal(hud_julius_error_quark(), 0, "HUD Julius listening daemon failed");
 
212
    g_source_remove(self->timeout_source);
 
213
    g_main_loop_quit(self->mainloop);
 
214
    return FALSE;
 
215
  }
 
216
 
 
217
  return TRUE;
 
218
}
 
219
 
 
220
static void
 
221
hud_julius_kill(GPid pid)
 
222
{
 
223
  kill(pid, SIGTERM);
 
224
}
 
225
 
 
226
static gboolean
 
227
hud_julius_listen (HudJulius *self, const gchar *gram, const gchar *hmm,
 
228
    const gchar *hlist, gchar **query, GError **error)
 
229
{
 
230
  gchar *program = hud_julius_get_daemon_path ();
 
231
  g_debug("Julius listening program [%s]", program);
 
232
 
 
233
  const gchar *argv[] =
 
234
  { program, "-input", "pulseaudio", "-gram", gram, "-h", hmm, "-hlist", hlist, NULL };
 
235
 
 
236
  /* These are used inside the callbacks */
 
237
  self->error = error;
 
238
  self->query = query;
 
239
  self->listen_emitted = FALSE;
 
240
  self->heard_something_emitted = FALSE;
 
241
 
 
242
  gint standard_output;
 
243
  GPid pid = 0;
 
244
 
 
245
  if (!g_spawn_async_with_pipes (NULL, (gchar **) argv, NULL, 0, NULL, NULL,
 
246
      &pid, NULL, &standard_output, NULL, error))
 
247
  {
 
248
    g_warning("Failed to to load Julius daemon");
 
249
    *query = NULL;
 
250
    *error = g_error_new_literal (hud_julius_error_quark (), 0,
 
251
        "Failed to load Julius daemon");
 
252
    g_free(program);
 
253
    return FALSE;
 
254
  }
 
255
 
 
256
  g_free(program);
 
257
 
 
258
  GIOChannel *channel;
 
259
 
 
260
  channel = g_io_channel_unix_new (standard_output);
 
261
  g_io_channel_set_flags (channel,
 
262
      g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, NULL );
 
263
  g_io_channel_set_encoding (channel, NULL, NULL );
 
264
 
 
265
  self->watch_source = g_io_add_watch (channel,
 
266
      G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 
267
               watch_function,
 
268
               self);
 
269
 
 
270
  self->mainloop = g_main_loop_new (NULL, FALSE);
 
271
  self->timeout_source = g_timeout_add (HUD_JULIUS_DEFAULT_TIMEOUT / 1000, timeout_quit_func, self);
 
272
  g_main_loop_run (self->mainloop);
 
273
  g_main_loop_unref (self->mainloop);
 
274
 
 
275
  g_io_channel_unref (channel);
 
276
  hud_julius_kill(pid);
 
277
  g_spawn_close_pid(pid);
 
278
 
 
279
  return (*self->error == NULL);
 
280
}
 
281
 
 
282
static void
 
283
free_func (gpointer data)
 
284
{
 
285
  g_ptr_array_free((GPtrArray*) data, TRUE);
 
286
}
 
287
 
 
288
static const gchar *VOCA_HEADER = "% NS_B\n"
 
289
"<s>             sil\n"
 
290
"\n"
 
291
"% NS_E\n"
 
292
"</s>            sil\n"
 
293
"\n";
 
294
 
 
295
static void
 
296
hud_julius_write_new_vocabulary_entry(GOutputStream* voca_output, GHashTable *voca, const gint voca_id, GHashTable *pronounciations, const gchar *word)
 
297
{
 
298
  g_hash_table_insert(voca, g_strdup(word), GINT_TO_POINTER(voca_id));
 
299
 
 
300
  gchar *voca_id_str = g_strdup_printf("TOKEN_%d", voca_id);
 
301
  gchar **phonetics_list = g_hash_table_lookup(pronounciations, word);
 
302
 
 
303
  /* We are writing:
 
304
   *
 
305
   * % <voca_id>:
 
306
   * <word> <phonetics 1>
 
307
   * <word> <phonetics 2>
 
308
   */
 
309
 
 
310
  /* we only need to write out the vocab entry for a new token */
 
311
  g_output_stream_write (voca_output, "% ", g_utf8_strlen ("% ", -1),
 
312
                              NULL, NULL );
 
313
  g_output_stream_write (voca_output, voca_id_str,
 
314
                g_utf8_strlen (voca_id_str, -1), NULL, NULL );
 
315
  g_output_stream_write (voca_output, ":\n", g_utf8_strlen (":\n", -1),
 
316
                      NULL, NULL );
 
317
 
 
318
  gchar **phonetics = phonetics_list;
 
319
  while (*phonetics)
 
320
  {
 
321
    gchar* lower = g_utf8_strdown(*phonetics, -1);
 
322
 
 
323
    g_output_stream_write (voca_output, word,
 
324
            g_utf8_strlen (word, -1), NULL, NULL );
 
325
    g_output_stream_write (voca_output, "\t",
 
326
                    g_utf8_strlen ("\t", -1), NULL, NULL );
 
327
    /* also add the phonetics */
 
328
    g_output_stream_write (voca_output, lower,
 
329
                            g_utf8_strlen (lower, -1), NULL, NULL );
 
330
    g_output_stream_write (voca_output, "\n", g_utf8_strlen ("\n", -1),
 
331
                  NULL, NULL );
 
332
    g_free(lower);
 
333
    phonetics++;
 
334
  }
 
335
 
 
336
  g_output_stream_write (voca_output, "\n", g_utf8_strlen ("\n", -1),
 
337
    NULL, NULL );
 
338
 
 
339
  g_free(voca_id_str);
 
340
}
 
341
 
 
342
/**
 
343
 * This writes a grammar entry for the whole command read out, and individual grammar entries
 
344
 * for each word in the command.
 
345
 */
 
346
static void
 
347
hud_julius_write_command(GOutputStream* grammar_output, GOutputStream* voca_output, GHashTable *voca, gint *voca_id_counter, GHashTable *pronounciations, GPtrArray *command)
 
348
{
 
349
  /* First we write a grammar entry as the complete sequence of words in the command */
 
350
  g_output_stream_write (grammar_output, "S : NS_B ", g_utf8_strlen ("S : NS_B ", -1),
 
351
              NULL, NULL );
 
352
 
 
353
  guint i;
 
354
  for (i = 0; i < command->len; ++i)
 
355
  {
 
356
    const gchar *word = g_ptr_array_index(command,  i);
 
357
    gint voca_id = GPOINTER_TO_INT(g_hash_table_lookup(voca, word));
 
358
 
 
359
    /* If this a new phonetic */
 
360
    if (voca_id == 0)
 
361
    {
 
362
      voca_id = ++(*voca_id_counter);
 
363
      hud_julius_write_new_vocabulary_entry(voca_output, voca, voca_id, pronounciations, word);
 
364
    }
 
365
 
 
366
    gchar *voca_id_str = g_strdup_printf("TOKEN_%d", voca_id);
 
367
 
 
368
    g_output_stream_write (grammar_output, voca_id_str,
 
369
        g_utf8_strlen (voca_id_str, -1), NULL, NULL );
 
370
    g_output_stream_write (grammar_output, " ", g_utf8_strlen (" ", -1),
 
371
                  NULL, NULL );
 
372
    g_free(voca_id_str);
 
373
  }
 
374
 
 
375
  g_output_stream_write (grammar_output, " NS_E\n",
 
376
            g_utf8_strlen (" NS_E\n", -1), NULL, NULL );
 
377
 
 
378
  /* Now we write a separate grammar entry for each word in the command */
 
379
  for (i = 0; i < command->len; ++i)
 
380
  {
 
381
    g_output_stream_write (grammar_output, "S : NS_B ", g_utf8_strlen ("S : NS_B ", -1),
 
382
                  NULL, NULL );
 
383
 
 
384
    const gchar *word = g_ptr_array_index(command, i);
 
385
    /* The voca_id will certainly be known as we've already written the while lot out once */
 
386
    gint voca_id = GPOINTER_TO_INT(g_hash_table_lookup(voca, word));
 
387
 
 
388
    gchar *voca_id_str = g_strdup_printf("TOKEN_%d", voca_id);
 
389
 
 
390
    g_output_stream_write (grammar_output, voca_id_str,
 
391
        g_utf8_strlen (voca_id_str, -1), NULL, NULL );
 
392
    g_output_stream_write (grammar_output, " ", g_utf8_strlen (" ", -1),
 
393
                  NULL, NULL );
 
394
    g_free(voca_id_str);
 
395
 
 
396
    g_output_stream_write (grammar_output, " NS_E\n",
 
397
        g_utf8_strlen (" NS_E\n", -1), NULL, NULL );
 
398
  }
 
399
}
 
400
 
 
401
static gboolean
 
402
hud_julius_build_grammar (HudJulius *self, GList *items, gchar **temp_dir, GError **error)
 
403
{
 
404
  *temp_dir = g_dir_make_tmp ("hud-julius-XXXXXX", error);
 
405
  if (*temp_dir == NULL )
 
406
  {
 
407
    g_warning("Failed to create temp dir [%s]", (*error)->message);
 
408
    return FALSE;
 
409
  }
 
410
 
 
411
  PronounceDict *dict = pronounce_dict_get_julius(error);
 
412
  if (dict == NULL)
 
413
  {
 
414
    rm_rf(*temp_dir);
 
415
    g_clear_pointer(temp_dir, g_free);
 
416
    return FALSE;
 
417
  }
 
418
 
 
419
  /* Get the pronounciations for the items */
 
420
  GHashTable *pronounciations = g_hash_table_new_full (g_str_hash, g_str_equal,
 
421
      g_free, (GDestroyNotify) g_strfreev);
 
422
  GPtrArray *command_list = g_ptr_array_new_with_free_func (free_func);
 
423
  GHashTable *unique_commands = g_hash_table_new(g_str_hash, g_str_equal);
 
424
  HudItemPronunciationData pronounciation_data =
 
425
  { pronounciations, self->alphanumeric_regex, command_list, dict, unique_commands };
 
426
  g_list_foreach (items, (GFunc) hud_item_insert_pronounciation,
 
427
      &pronounciation_data);
 
428
  g_hash_table_destroy(unique_commands);
 
429
 
 
430
  if (command_list->len == 0)
 
431
  {
 
432
    *error = g_error_new_literal(hud_julius_error_quark(), 0, "Could not build Julius grammar. Is julius-voxforge installed?");
 
433
    rm_rf(*temp_dir);
 
434
    g_clear_pointer(temp_dir, g_free);
 
435
    return FALSE;
 
436
  }
 
437
 
 
438
  gint voca_id_counter = 0;
 
439
  GHashTable *voca = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
 
440
      NULL );
 
441
 
 
442
  gchar *voca_path = g_build_filename (*temp_dir, "hud.voca", NULL );
 
443
  GFile *voca_file = g_file_new_for_path (voca_path);
 
444
  *error = NULL;
 
445
  GOutputStream* voca_output = G_OUTPUT_STREAM(g_file_create (voca_file,
 
446
          G_FILE_CREATE_PRIVATE, NULL, error ));
 
447
  if (voca_output == NULL )
 
448
  {
 
449
    g_warning("Failed to open voca file [%s]", (*error)->message);
 
450
 
 
451
    g_hash_table_destroy(voca);
 
452
    g_hash_table_destroy(pronounciations);
 
453
    g_ptr_array_free (command_list, TRUE);
 
454
 
 
455
    g_object_unref (voca_output);
 
456
    g_object_unref (voca_file);
 
457
 
 
458
    rm_rf(*temp_dir);
 
459
    g_clear_pointer(temp_dir, g_free);
 
460
 
 
461
    return FALSE;
 
462
  }
 
463
 
 
464
  gchar *grammar_path = g_build_filename (*temp_dir, "hud.grammar", NULL );
 
465
  GFile *grammar_file = g_file_new_for_path (grammar_path);
 
466
  error = NULL;
 
467
  GOutputStream* grammar_output = G_OUTPUT_STREAM(g_file_create (grammar_file,
 
468
          G_FILE_CREATE_PRIVATE, NULL, error ));
 
469
  if (grammar_output == NULL )
 
470
  {
 
471
    g_warning("Failed to open grammar file [%s]", (*error)->message);
 
472
 
 
473
    g_hash_table_destroy(voca);
 
474
    g_hash_table_destroy(pronounciations);
 
475
    g_ptr_array_free (command_list, TRUE);
 
476
 
 
477
    g_object_unref (voca_output);
 
478
    g_object_unref (voca_file);
 
479
 
 
480
    g_object_unref (grammar_output);
 
481
    g_object_unref (grammar_file);
 
482
 
 
483
    rm_rf(*temp_dir);
 
484
    g_clear_pointer(temp_dir, g_free);
 
485
 
 
486
    return FALSE;
 
487
  }
 
488
 
 
489
  g_output_stream_write (voca_output, VOCA_HEADER,
 
490
      g_utf8_strlen (VOCA_HEADER, -1), NULL, NULL );
 
491
 
 
492
  guint i;
 
493
  for (i = 0; i < command_list->len; ++i)
 
494
  {
 
495
    GPtrArray *command = g_ptr_array_index(command_list, i);
 
496
    hud_julius_write_command(grammar_output, voca_output, voca, &voca_id_counter, pronounciations, command);
 
497
  }
 
498
 
 
499
  g_hash_table_destroy(voca);
 
500
  g_hash_table_destroy(pronounciations);
 
501
  g_ptr_array_free (command_list, TRUE);
 
502
 
 
503
  g_object_unref (voca_output);
 
504
  g_object_unref (voca_file);
 
505
 
 
506
  g_object_unref (grammar_output);
 
507
  g_object_unref (grammar_file);
 
508
 
 
509
  g_free(voca_path);
 
510
  g_free(grammar_path);
 
511
 
 
512
  /* Now compile the grammar */
 
513
  const gchar *argv[] = { "/usr/bin/mkdfa", "hud", NULL };
 
514
  error = NULL;
 
515
  int exit_status = 0;
 
516
  char *standard_output = NULL;
 
517
  char *standard_error = NULL;
 
518
  if (!g_spawn_sync (*temp_dir, (gchar **)argv, NULL, 0, NULL, NULL, &standard_output,
 
519
      &standard_error, &exit_status, error))
 
520
  {
 
521
    g_warning("Compiling grammar failed: [%s]", (*error)->message);
 
522
    g_debug("Compilation errors:\n%s", standard_error);
 
523
 
 
524
    g_free(standard_output);
 
525
    g_free(standard_error);
 
526
 
 
527
    rm_rf(*temp_dir);
 
528
    g_clear_pointer(temp_dir, g_free);
 
529
 
 
530
    return FALSE;
 
531
  }
 
532
 
 
533
  g_debug("Compilation output:\n%s", standard_output);
 
534
 
 
535
  g_free(standard_output);
 
536
  g_free(standard_error);
 
537
 
 
538
  return TRUE;
 
539
}
 
540
 
 
541
static void rm_rf(const gchar *path)
 
542
{
 
543
  GError *error = NULL;
 
544
  GDir *dir = g_dir_open(path, 0, &error);
 
545
  if (dir == NULL)
 
546
  {
 
547
    g_warning("Could not open directory [%s] for deletion: [%s]", path, error->message);
 
548
    g_error_free(error);
 
549
    return;
 
550
  }
 
551
  const gchar *file_name;
 
552
  gboolean remove_error = FALSE;
 
553
  while ((file_name = g_dir_read_name(dir)) && !remove_error)
 
554
  {
 
555
    gchar *file_path = g_build_filename(path, file_name, NULL);
 
556
    g_debug("removing file [%s]", file_path);
 
557
    if (g_remove(file_path) != 0)
 
558
    {
 
559
      g_warning("Unable to remove file [%s]", file_path);
 
560
      remove_error = TRUE;
 
561
    }
 
562
    g_free(file_path);
 
563
  }
 
564
  g_dir_close(dir);
 
565
  if (!remove_error)
 
566
  {
 
567
    g_debug("removing dir [%s]", path);
 
568
    g_rmdir(path);
 
569
  } else
 
570
  {
 
571
    g_debug("not removing directory [%s]", path);
 
572
  }
 
573
}
 
574
 
 
575
static gboolean
 
576
hud_julius_voice_query (HudVoice *voice, HudSource *source, gchar **result, GError **error)
 
577
{
 
578
  g_return_val_if_fail(HUD_IS_JULIUS(voice), FALSE);
 
579
  HudJulius *self = HUD_JULIUS(voice);
 
580
 
 
581
  if (source == NULL) {
 
582
    /* No active window, that's fine, but we'll just move on */
 
583
    *result = NULL;
 
584
    *error = g_error_new_literal(hud_julius_error_quark(), 0, "Active source is null");
 
585
    return FALSE;
 
586
  }
 
587
 
 
588
  GList *items = hud_source_get_items(source);
 
589
  if (items == NULL) {
 
590
    /* The active window doesn't have items, that's cool.  We'll move on. */
 
591
    return TRUE;
 
592
  }
 
593
 
 
594
  gchar *temp_dir = NULL;
 
595
  if (!hud_julius_build_grammar(self, items, &temp_dir, error))
 
596
  {
 
597
    g_list_free_full(items, g_object_unref);
 
598
    return FALSE;
 
599
  }
 
600
 
 
601
  gchar *gram = g_build_filename(temp_dir, "hud", NULL);
 
602
  gchar *hmm = g_build_filename(JULIUS_DICT_PATH, "hmmdefs", NULL);
 
603
  gchar *hlist = g_build_filename(JULIUS_DICT_PATH, "tiedlist", NULL);
 
604
 
 
605
  gboolean success = hud_julius_listen (self, gram, hmm, hlist, result, error);
 
606
 
 
607
  rm_rf(temp_dir);
 
608
 
 
609
  g_list_free_full(items, g_object_unref);
 
610
  g_free(gram);
 
611
  g_free(hmm);
 
612
  g_free(hlist);
 
613
  g_free(temp_dir);
 
614
 
 
615
  return success;
 
616
}
 
617
 
 
618
gboolean
 
619
hud_julius_is_installed()
 
620
{
 
621
  gchar *filename = hud_julius_get_daemon_path();
 
622
  gboolean result = g_file_test(filename, G_FILE_TEST_EXISTS);
 
623
  g_free(filename);
 
624
  return result;
 
625
}
 
626
 
 
627
HudJulius *
 
628
hud_julius_new(HudQueryIfaceComCanonicalHudQuery * skel)
 
629
{
 
630
  HudJulius *self = g_object_new (HUD_TYPE_JULIUS, NULL);
 
631
  self->skel = g_object_ref(skel);
 
632
 
 
633
  return self;
 
634
}