~ubuntu-branches/ubuntu/precise/empathy/precise-proposed-201205180810

« back to all changes in this revision

Viewing changes to libempathy-gtk/empathy-sound.c

  • Committer: Bazaar Package Importer
  • Author(s): Brian Curtis, Brian Curtis, Ken VanDine
  • Date: 2011-06-01 10:35:24 UTC
  • mfrom: (1.1.70 upstream) (6.3.44 experimental)
  • Revision ID: james.westby@ubuntu.com-20110601103524-wx3wgp71394730jt
Tags: 3.1.1-1ubuntu1
[ Brian Curtis ]
* Merge with Debian experimental, remaining Ubuntu changes:
* debian/control:
  - Drop geoclue/mapping build-depends (they are in Universe)
  - Add Vcz-Bzr link
  - Add Suggests on telepathy-idle
  - Bump telepathy-butterfly, telepathy-haze to recommends
  - Don't recommend the freedesktop sound theme we have an ubuntu one
  - Add build depend for libunity-dev
* debian/rules:
  - Use autoreconf.mk
  - Disable map and location
* debian/empathy.install:
  - Install message indicator configuration
* debian/indicators/empathy:
  - Message indicator configuration
* debian/patches/01_lpi.patch:
  - Add Launchpad integration
* debian/patches/10_use_notify_osd_icons.patch:
  - Use the notify-osd image for new messages
* debian/patches/34_start_raised_execpt_in_session.patch
  - If not started with the session, we should always raise
* debian/patches/36_chat_window_default_size.patch:
  - Make the default chat window size larger
* debian/patches/37_facebook_default.patch:
  - Make facebook the default chat account type
* debian/patches/38_lp_569289.patch
  - Set freenode as default IRC network for new IRC accounts 
* debian/patches/41_unity_launcher_progress.patch
  - Display file transfer progress in the unity launcher

[ Ken VanDine ]
* debian/control
  - build depend on libgcr-3-dev instead of libgcr-dev
  - dropped build depends for libindicate, we will use telepathy-indicator
  - Depend on dconf-gsettings-backend | gsettings-backend
  - Added a Recommends for telepathy-indicator
* +debian/empathy.gsettings-override
  - Added an override for notifications-focus
* debian/patches/series
  - commented out 23_idomessagedialog_for_voip_and_ft.patch, until ido has 
    been ported to gtk3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * empathy-sound.c - Various sound related utility functions.
3
 
 * Copyright (C) 2009 Collabora Ltd.
4
 
 *
5
 
 * This library is free software; you can redistribute it and/or
6
 
 * modify it under the terms of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation; either
8
 
 * version 2.1 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 * Lesser General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Lesser General Public
16
 
 * License along with this library; if not, write to the Free Software
17
 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 */
19
 
 
20
 
#include <config.h>
21
 
 
22
 
#include "empathy-sound.h"
23
 
 
24
 
#include <canberra-gtk.h>
25
 
#include <glib/gi18n-lib.h>
26
 
#include <gtk/gtk.h>
27
 
 
28
 
#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
29
 
#include <libempathy/empathy-debug.h>
30
 
#include <libempathy/empathy-gsettings.h>
31
 
#include <libempathy/empathy-utils.h>
32
 
 
33
 
typedef struct {
34
 
  EmpathySound sound_id;
35
 
  const char * event_ca_id;
36
 
  const char * event_ca_description;
37
 
  const char * key;
38
 
} EmpathySoundEntry;
39
 
 
40
 
typedef struct {
41
 
  GtkWidget *widget;
42
 
  gint sound_id;
43
 
  guint play_interval;
44
 
  guint replay_timeout_id;
45
 
} EmpathyRepeatableSound;
46
 
 
47
 
/* NOTE: these entries MUST be in the same order than EmpathySound enum */
48
 
static EmpathySoundEntry sound_entries[LAST_EMPATHY_SOUND] = {
49
 
  { EMPATHY_SOUND_MESSAGE_INCOMING, "message-new-instant",
50
 
    N_("Received an instant message"), EMPATHY_PREFS_SOUNDS_INCOMING_MESSAGE } ,
51
 
  { EMPATHY_SOUND_MESSAGE_OUTGOING, "message-sent-instant",
52
 
    N_("Sent an instant message"), EMPATHY_PREFS_SOUNDS_OUTGOING_MESSAGE } ,
53
 
  { EMPATHY_SOUND_CONVERSATION_NEW, "message-new-instant",
54
 
    N_("Incoming chat request"), EMPATHY_PREFS_SOUNDS_NEW_CONVERSATION },
55
 
  { EMPATHY_SOUND_CONTACT_CONNECTED, "service-login",
56
 
    N_("Contact connected"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGIN },
57
 
  { EMPATHY_SOUND_CONTACT_DISCONNECTED, "service-logout",
58
 
    N_("Contact disconnected"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGOUT },
59
 
  { EMPATHY_SOUND_ACCOUNT_CONNECTED, "service-login",
60
 
    N_("Connected to server"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGIN },
61
 
  { EMPATHY_SOUND_ACCOUNT_DISCONNECTED, "service-logout",
62
 
    N_("Disconnected from server"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGOUT },
63
 
  { EMPATHY_SOUND_PHONE_INCOMING, "phone-incoming-call",
64
 
    N_("Incoming voice call"), NULL },
65
 
  { EMPATHY_SOUND_PHONE_OUTGOING, "phone-outgoing-calling",
66
 
    N_("Outgoing voice call"), NULL },
67
 
  { EMPATHY_SOUND_PHONE_HANGUP, "phone-hangup",
68
 
    N_("Voice call ended"), NULL },
69
 
};
70
 
 
71
 
/* An hash table containing currently repeating sounds. The format is the
72
 
 * following:
73
 
 * Key: An EmpathySound
74
 
 * Value : The EmpathyRepeatableSound associated with that EmpathySound. */
75
 
static GHashTable *repeating_sounds;
76
 
 
77
 
static gboolean
78
 
empathy_sound_pref_is_enabled (EmpathySound sound_id)
79
 
{
80
 
  EmpathySoundEntry *entry;
81
 
  GSettings *gsettings = g_settings_new (EMPATHY_PREFS_SOUNDS_SCHEMA);
82
 
  gboolean res;
83
 
 
84
 
  entry = &(sound_entries[sound_id]);
85
 
  g_return_val_if_fail (entry->sound_id == sound_id, FALSE);
86
 
 
87
 
  if (entry->key == NULL)
88
 
    {
89
 
      res = TRUE;
90
 
      goto finally;
91
 
    }
92
 
 
93
 
  res = g_settings_get_boolean (gsettings, EMPATHY_PREFS_SOUNDS_ENABLED);
94
 
 
95
 
  if (!res)
96
 
    goto finally;
97
 
 
98
 
  if (!empathy_check_available_state ())
99
 
    {
100
 
      if (g_settings_get_boolean (gsettings,
101
 
            EMPATHY_PREFS_SOUNDS_DISABLED_AWAY))
102
 
        {
103
 
          res = FALSE;
104
 
          goto finally;
105
 
        }
106
 
    }
107
 
 
108
 
  res = g_settings_get_boolean (gsettings, entry->key);
109
 
 
110
 
finally:
111
 
  g_object_unref (gsettings);
112
 
 
113
 
  return res;
114
 
}
115
 
 
116
 
/**
117
 
 * empathy_sound_stop:
118
 
 * @sound_id: The #EmpathySound to stop playing.
119
 
 *
120
 
 * Stop playing a sound. If it has been stated in loop with
121
 
 * empathy_sound_start_playing(), it will also stop replaying.
122
 
 */
123
 
void
124
 
empathy_sound_stop (EmpathySound sound_id)
125
 
{
126
 
  EmpathySoundEntry *entry;
127
 
 
128
 
  g_return_if_fail (sound_id < LAST_EMPATHY_SOUND);
129
 
 
130
 
  entry = &(sound_entries[sound_id]);
131
 
  g_return_if_fail (entry->sound_id == sound_id);
132
 
 
133
 
  if (repeating_sounds != NULL)
134
 
    {
135
 
      EmpathyRepeatableSound *repeatable_sound;
136
 
 
137
 
      repeatable_sound = g_hash_table_lookup (repeating_sounds,
138
 
          GINT_TO_POINTER (sound_id));
139
 
      if (repeatable_sound != NULL)
140
 
        {
141
 
          /* The sound must be stopped... If it is waiting for replay, remove
142
 
           * it from hash table to cancel. Otherwise we'll cancel the sound
143
 
           * being played. */
144
 
          if (repeatable_sound->replay_timeout_id != 0)
145
 
            {
146
 
              g_hash_table_remove (repeating_sounds, GINT_TO_POINTER (sound_id));
147
 
              return;
148
 
            }
149
 
        }
150
 
    }
151
 
 
152
 
  ca_context_cancel (ca_gtk_context_get (), entry->sound_id);
153
 
}
154
 
 
155
 
static gboolean
156
 
empathy_sound_play_internal (GtkWidget *widget, EmpathySound sound_id,
157
 
  ca_finish_callback_t callback, gpointer user_data)
158
 
{
159
 
  EmpathySoundEntry *entry;
160
 
  ca_context *c;
161
 
  ca_proplist *p = NULL;
162
 
 
163
 
  entry = &(sound_entries[sound_id]);
164
 
  g_return_val_if_fail (entry->sound_id == sound_id, FALSE);
165
 
 
166
 
  c = ca_gtk_context_get ();
167
 
  ca_context_cancel (c, entry->sound_id);
168
 
 
169
 
  DEBUG ("Play sound \"%s\" (%s)",
170
 
         entry->event_ca_id,
171
 
         entry->event_ca_description);
172
 
 
173
 
  if (ca_proplist_create (&p) < 0)
174
 
    goto failed;
175
 
 
176
 
  if (ca_proplist_sets (p, CA_PROP_EVENT_ID, entry->event_ca_id) < 0)
177
 
    goto failed;
178
 
 
179
 
  if (ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION,
180
 
          gettext (entry->event_ca_description)) < 0)
181
 
    goto failed;
182
 
 
183
 
  if (ca_gtk_proplist_set_for_widget (p, widget) < 0)
184
 
    goto failed;
185
 
 
186
 
  ca_context_play_full (ca_gtk_context_get (), entry->sound_id, p, callback,
187
 
      user_data);
188
 
 
189
 
  ca_proplist_destroy (p);
190
 
 
191
 
  return TRUE;
192
 
 
193
 
failed:
194
 
  if (p != NULL)
195
 
    ca_proplist_destroy (p);
196
 
 
197
 
  return FALSE;
198
 
}
199
 
 
200
 
/**
201
 
 * empathy_sound_play_full:
202
 
 * @widget: The #GtkWidget from which the sound is originating.
203
 
 * @sound_id: The #EmpathySound to play.
204
 
 * @callback: The #ca_finish_callback_t function that will be called when the
205
 
 *            sound  has stopped playing.
206
 
 * @user_data: user data to pass to the function.
207
 
 *
208
 
 * Plays a sound.
209
 
 *
210
 
 * Returns %TRUE if the sound has successfully started playing, otherwise
211
 
 * returning %FALSE and @callback won't be called.
212
 
 *
213
 
 * This function returns %FALSE if the sound is already playing in loop using
214
 
 * %empathy_sound_start_playing.
215
 
 *
216
 
 * This function returns %FALSE if the sound is disabled in empathy preferences.
217
 
 *
218
 
 * Return value: %TRUE if the sound has successfully started playing, %FALSE
219
 
 *               otherwise.
220
 
 */
221
 
gboolean
222
 
empathy_sound_play_full (GtkWidget *widget, EmpathySound sound_id,
223
 
  ca_finish_callback_t callback, gpointer user_data)
224
 
{
225
 
  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
226
 
  g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE);
227
 
 
228
 
  if (!empathy_sound_pref_is_enabled (sound_id))
229
 
    return FALSE;
230
 
 
231
 
  /* The sound might already be playing repeatedly. If it's the case, we
232
 
   * immediadely return since there's no need to make it play again */
233
 
  if (repeating_sounds != NULL &&
234
 
      g_hash_table_lookup (repeating_sounds, GINT_TO_POINTER (sound_id)) != NULL)
235
 
    return FALSE;
236
 
 
237
 
  return empathy_sound_play_internal (widget, sound_id, callback, user_data);
238
 
}
239
 
 
240
 
/**
241
 
 * empathy_sound_play:
242
 
 * @widget: The #GtkWidget from which the sound is originating.
243
 
 * @sound_id: The #EmpathySound to play.
244
 
 *
245
 
 * Plays a sound. See %empathy_sound_play_full for details.'
246
 
 *
247
 
 * Return value: %TRUE if the sound has successfully started playing, %FALSE
248
 
 *               otherwise.
249
 
 */
250
 
gboolean
251
 
empathy_sound_play (GtkWidget *widget, EmpathySound sound_id)
252
 
{
253
 
  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
254
 
  g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE);
255
 
 
256
 
  return empathy_sound_play_full (widget, sound_id, NULL, NULL);
257
 
}
258
 
 
259
 
static void playing_finished_cb (ca_context *c, guint id, int error_code,
260
 
  gpointer user_data);
261
 
 
262
 
static gboolean
263
 
playing_timeout_cb (gpointer data)
264
 
{
265
 
  EmpathyRepeatableSound *repeatable_sound = data;
266
 
  gboolean playing;
267
 
 
268
 
  repeatable_sound->replay_timeout_id = 0;
269
 
 
270
 
  playing = empathy_sound_play_internal (repeatable_sound->widget,
271
 
      repeatable_sound->sound_id, playing_finished_cb, data);
272
 
 
273
 
  if (!playing)
274
 
    {
275
 
      DEBUG ("Failed to replay sound, stop repeating");
276
 
      g_hash_table_remove (repeating_sounds,
277
 
          GINT_TO_POINTER (repeatable_sound->sound_id));
278
 
    }
279
 
 
280
 
  return FALSE;
281
 
}
282
 
 
283
 
static void
284
 
playing_finished_cb (ca_context *c, guint id, int error_code,
285
 
  gpointer user_data)
286
 
{
287
 
  EmpathyRepeatableSound *repeatable_sound = user_data;
288
 
 
289
 
  if (error_code != CA_SUCCESS)
290
 
    {
291
 
      DEBUG ("Error: %s", ca_strerror (error_code));
292
 
      g_hash_table_remove (repeating_sounds,
293
 
          GINT_TO_POINTER (repeatable_sound->sound_id));
294
 
      return;
295
 
    }
296
 
 
297
 
  repeatable_sound->replay_timeout_id = g_timeout_add (
298
 
      repeatable_sound->play_interval, playing_timeout_cb, user_data);
299
 
}
300
 
 
301
 
static void
302
 
empathy_sound_widget_destroyed_cb (GtkWidget *widget, gpointer user_data)
303
 
{
304
 
  EmpathyRepeatableSound *repeatable_sound = user_data;
305
 
 
306
 
  /* The sound must be stopped... If it is waiting for replay, remove
307
 
   * it from hash table to cancel. Otherwise playing_finished_cb will be
308
 
   * called with an error. */
309
 
  if (repeatable_sound->replay_timeout_id != 0)
310
 
    {
311
 
      g_hash_table_remove (repeating_sounds,
312
 
          GINT_TO_POINTER (repeatable_sound->sound_id));
313
 
    }
314
 
}
315
 
 
316
 
static void
317
 
repeating_sounds_item_delete (gpointer data)
318
 
{
319
 
  EmpathyRepeatableSound *repeatable_sound = data;
320
 
 
321
 
  if (repeatable_sound->replay_timeout_id != 0)
322
 
    g_source_remove (repeatable_sound->replay_timeout_id);
323
 
 
324
 
  g_signal_handlers_disconnect_by_func (repeatable_sound->widget,
325
 
      empathy_sound_widget_destroyed_cb, repeatable_sound);
326
 
 
327
 
  g_slice_free (EmpathyRepeatableSound, repeatable_sound);
328
 
}
329
 
 
330
 
/**
331
 
 * empathy_sound_start_playing:
332
 
 * @widget: The #GtkWidget from which the sound is originating.
333
 
 * @sound_id: The #EmpathySound to play.
334
 
 * @timeout_before_replay: The amount of time, in milliseconds, between two
335
 
 *                         consecutive play.
336
 
 *
337
 
 * Start playing a sound in loop. To stop the sound, call empathy_call_stop ()
338
 
 * by passing it the same @sound_id. Note that if you start playing a sound
339
 
 * multiple times, you'll have to call %empathy_sound_stop the same number of
340
 
 * times.
341
 
 *
342
 
 * Return value: %TRUE if the sound has successfully started playing.
343
 
 */
344
 
gboolean
345
 
empathy_sound_start_playing (GtkWidget *widget, EmpathySound sound_id,
346
 
    guint timeout_before_replay)
347
 
{
348
 
  EmpathyRepeatableSound *repeatable_sound;
349
 
  gboolean playing = FALSE;
350
 
 
351
 
  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
352
 
  g_return_val_if_fail (sound_id < LAST_EMPATHY_SOUND, FALSE);
353
 
 
354
 
  if (!empathy_sound_pref_is_enabled (sound_id))
355
 
    return FALSE;
356
 
 
357
 
  if (repeating_sounds == NULL)
358
 
    {
359
 
      repeating_sounds = g_hash_table_new_full (g_direct_hash, g_direct_equal,
360
 
          NULL, repeating_sounds_item_delete);
361
 
    }
362
 
  else if (g_hash_table_lookup (repeating_sounds,
363
 
               GINT_TO_POINTER (sound_id)) != NULL)
364
 
    {
365
 
      /* The sound is already playing in loop. No need to continue. */
366
 
      return FALSE;
367
 
    }
368
 
 
369
 
  repeatable_sound = g_slice_new0 (EmpathyRepeatableSound);
370
 
  repeatable_sound->widget = widget;
371
 
  repeatable_sound->sound_id = sound_id;
372
 
  repeatable_sound->play_interval = timeout_before_replay;
373
 
  repeatable_sound->replay_timeout_id = 0;
374
 
 
375
 
  g_hash_table_insert (repeating_sounds, GINT_TO_POINTER (sound_id),
376
 
      repeatable_sound);
377
 
 
378
 
  g_signal_connect (G_OBJECT (widget), "destroy",
379
 
      G_CALLBACK (empathy_sound_widget_destroyed_cb),
380
 
      repeatable_sound);
381
 
 
382
 
  playing = empathy_sound_play_internal (widget, sound_id, playing_finished_cb,
383
 
        repeatable_sound);
384
 
 
385
 
  if (!playing)
386
 
      g_hash_table_remove (repeating_sounds, GINT_TO_POINTER (sound_id));
387
 
 
388
 
  return playing;
389
 
}