Mercurial > pidgin
annotate src/gtksound.c @ 10562:e06da39b467c
[gaim-migrate @ 11942]
This will prevent the connection process from hanging when the DNS lookup fails. We need to call the callback function regardless of whether the lookup succeeded. (This is in the DNS lookup functionality that is currently #ifdef _WIN32, but is actually portable),
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Tue, 01 Feb 2005 05:02:40 +0000 |
parents | 2a132b73a6e6 |
children | 68083504217c |
rev | line source |
---|---|
5684 | 1 /* |
10297
ec140184437b
[gaim-migrate @ 11480]
Luke Schierer <lschiere@pidgin.im>
parents:
10158
diff
changeset
|
2 * @file gtksound.h GTK+ Sound |
ec140184437b
[gaim-migrate @ 11480]
Luke Schierer <lschiere@pidgin.im>
parents:
10158
diff
changeset
|
3 * @ingroup gtkui |
ec140184437b
[gaim-migrate @ 11480]
Luke Schierer <lschiere@pidgin.im>
parents:
10158
diff
changeset
|
4 * |
5684 | 5 * gaim |
6 * | |
8046 | 7 * Gaim is the legal property of its developers, whose names are too numerous |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
5684 | 10 * |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 * | |
25 */ | |
9791 | 26 #include "internal.h" |
27 #include "gtkgaim.h" | |
5684 | 28 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
29 #ifdef _WIN32 |
5684 | 30 #include <windows.h> |
31 #include <mmsystem.h> | |
32 #endif | |
33 | |
34 #ifdef USE_AO | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
35 # include <ao/ao.h> |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
36 # include <audiofile.h> |
5684 | 37 #endif /* USE_AO */ |
38 | |
39 #ifdef USE_NAS_AUDIO | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
40 # include <audio/audiolib.h> |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
41 # include <audio/soundlib.h> |
5684 | 42 #endif /* USE_NAS_AUDIO */ |
43 | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
44 #include "debug.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
45 #include "notify.h" |
5684 | 46 #include "prefs.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
47 #include "sound.h" |
7465 | 48 #include "util.h" |
5684 | 49 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
50 #include "gtksound.h" |
5684 | 51 |
52 struct gaim_sound_event { | |
53 char *label; | |
54 char *pref; | |
55 char *def; | |
56 }; | |
57 | |
10074 | 58 #define PLAY_SOUND_TIMEOUT 15000 |
5684 | 59 |
10320 | 60 static guint mute_login_sounds_timeout = 0; |
5684 | 61 static gboolean mute_login_sounds = FALSE; |
6199 | 62 static gboolean sound_initialized = FALSE; |
5684 | 63 |
64 static struct gaim_sound_event sounds[GAIM_NUM_SOUNDS] = { | |
10158 | 65 {N_("Buddy logs in"), "login", "login.wav"}, |
66 {N_("Buddy logs out"), "logout", "logout.wav"}, | |
5684 | 67 {N_("Message received"), "im_recv", "receive.wav"}, |
68 {N_("Message received begins conversation"), "first_im_recv", "receive.wav"}, | |
69 {N_("Message sent"), "send_im", "send.wav"}, | |
10158 | 70 {N_("Person enters chat"), "join_chat", "login.wav"}, |
71 {N_("Person leaves chat"), "left_chat", "logout.wav"}, | |
5684 | 72 {N_("You talk in chat"), "send_chat_msg", "send.wav"}, |
73 {N_("Others talk in chat"), "chat_msg_recv", "receive.wav"}, | |
74 /* this isn't a terminator, it's the buddy pounce default sound event ;-) */ | |
10158 | 75 {NULL, "pounce_default", "alert.wav"}, |
76 {N_("Someone says your name in chat"), "nick_said", "alert.wav"} | |
5684 | 77 }; |
78 | |
79 #ifdef USE_AO | |
80 static int ao_driver = -1; | |
81 #endif /* USE_AO */ | |
82 | |
10320 | 83 static gboolean |
84 mute_login_sounds_cb(gpointer data) | |
85 { | |
86 mute_login_sounds = FALSE; | |
87 mute_login_sounds_timeout = 0; | |
88 return FALSE; | |
89 } | |
90 | |
91 /* | |
92 * We mute sounds for the 10 seconds after you log in so that | |
93 * you don't get flooded with sounds when the blist shows all | |
94 * your buddies logging in. | |
95 */ | |
96 static void | |
97 account_signon_cb(GaimConnection *gc, gpointer data) | |
98 { | |
99 if (mute_login_sounds_timeout != 0) | |
100 g_source_remove(mute_login_sounds_timeout); | |
101 mute_login_sounds = TRUE; | |
102 mute_login_sounds_timeout = gaim_timeout_add(10000, mute_login_sounds_cb, NULL); | |
103 } | |
104 | |
10322 | 105 static void |
106 _pref_sound_method_changed(const char *name, GaimPrefType type, | |
107 gpointer val, gpointer data) { | |
108 if(type != GAIM_PREF_STRING || strcmp(name, "/gaim/gtk/sound/method")) | |
109 return; | |
110 | |
111 sound_initialized = TRUE; | |
112 | |
113 #ifdef USE_AO | |
114 ao_driver = -1; | |
115 | |
116 if(!strcmp(val, "esd")) | |
117 ao_driver = ao_driver_id("esd"); | |
118 else if(!strcmp(val, "arts")) | |
119 ao_driver = ao_driver_id("arts"); | |
120 else if(!strcmp(val, "automatic")) | |
121 ao_driver = ao_default_driver_id(); | |
122 | |
123 if(ao_driver != -1) { | |
124 ao_info *info = ao_driver_info(ao_driver); | |
125 gaim_debug_info("sound", | |
126 "Sound output driver loaded: %s\n", info->name); | |
127 } | |
128 #endif /* USE_AO */ | |
129 #ifdef USE_NAS | |
130 if (!strcmp(val, "nas")) | |
131 gaim_debug_info("sound", | |
132 "Sound output driver loaded: NAS output\n"); | |
133 #endif /* USE_NAS */ | |
134 } | |
135 | |
136 const char * | |
137 gaim_gtk_sound_get_event_option(GaimSoundEventID event) | |
138 { | |
139 if(event >= GAIM_NUM_SOUNDS) | |
140 return 0; | |
141 | |
142 return sounds[event].pref; | |
143 } | |
144 | |
145 char * | |
146 gaim_gtk_sound_get_event_label(GaimSoundEventID event) | |
147 { | |
148 if(event >= GAIM_NUM_SOUNDS) | |
149 return NULL; | |
150 | |
151 return sounds[event].label; | |
152 } | |
153 | |
154 void * | |
155 gaim_gtk_sound_get_handle() | |
156 { | |
157 static int handle; | |
158 | |
159 return &handle; | |
160 } | |
161 | |
162 static void | |
163 gaim_gtk_sound_init(void) | |
5684 | 164 { |
10320 | 165 void *gtk_sound_handle = gaim_gtk_sound_get_handle(); |
166 | |
167 gaim_signal_connect(gaim_connections_get_handle(), "signed-on", | |
168 gtk_sound_handle, GAIM_CALLBACK(account_signon_cb), | |
169 NULL); | |
170 | |
5684 | 171 gaim_prefs_add_none("/gaim/gtk/sound"); |
172 gaim_prefs_add_none("/gaim/gtk/sound/enabled"); | |
173 gaim_prefs_add_none("/gaim/gtk/sound/file"); | |
174 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/login", TRUE); | |
175 gaim_prefs_add_string("/gaim/gtk/sound/file/login", ""); | |
176 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/logout", TRUE); | |
177 gaim_prefs_add_string("/gaim/gtk/sound/file/logout", ""); | |
178 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/im_recv", TRUE); | |
179 gaim_prefs_add_string("/gaim/gtk/sound/file/im_recv", ""); | |
180 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/first_im_recv", FALSE); | |
181 gaim_prefs_add_string("/gaim/gtk/sound/file/first_im_recv", ""); | |
182 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_im", TRUE); | |
183 gaim_prefs_add_string("/gaim/gtk/sound/file/send_im", ""); | |
184 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/join_chat", FALSE); | |
185 gaim_prefs_add_string("/gaim/gtk/sound/file/join_chat", ""); | |
186 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/left_chat", FALSE); | |
187 gaim_prefs_add_string("/gaim/gtk/sound/file/left_chat", ""); | |
188 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_chat_msg", FALSE); | |
189 gaim_prefs_add_string("/gaim/gtk/sound/file/send_chat_msg", ""); | |
190 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/chat_msg_recv", FALSE); | |
191 gaim_prefs_add_string("/gaim/gtk/sound/file/chat_msg_recv", ""); | |
192 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/nick_said", FALSE); | |
193 gaim_prefs_add_string("/gaim/gtk/sound/file/nick_said", ""); | |
7460
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
194 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/pounce_default", TRUE); |
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
195 gaim_prefs_add_string("/gaim/gtk/sound/file/pounce_default", ""); |
8633 | 196 gaim_prefs_add_bool("/gaim/gtk/sound/conv_focus", TRUE); |
10074 | 197 gaim_prefs_add_bool("/gaim/gtk/sound/mute", FALSE); |
5684 | 198 gaim_prefs_add_string("/gaim/gtk/sound/command", ""); |
199 gaim_prefs_add_string("/gaim/gtk/sound/method", "automatic"); | |
200 | |
201 #ifdef USE_AO | |
10322 | 202 gaim_debug_info("sound", "Initializing sound output drivers.\n"); |
5684 | 203 ao_initialize(); |
204 #endif /* USE_AO */ | |
205 | |
10087 | 206 gaim_prefs_connect_callback(gaim_gtk_sound_get_handle(), "/gaim/gtk/sound/method", |
5794
5e93fc46d1af
[gaim-migrate @ 6219]
Christian Hammond <chipx86@chipx86.com>
parents:
5684
diff
changeset
|
207 _pref_sound_method_changed, NULL); |
5684 | 208 } |
209 | |
10322 | 210 static void |
211 gaim_gtk_sound_uninit(void) | |
5684 | 212 { |
213 #ifdef USE_AO | |
214 ao_shutdown(); | |
215 #endif | |
6199 | 216 sound_initialized = FALSE; |
5684 | 217 } |
218 | |
10322 | 219 #ifdef USE_NAS_AUDIO |
220 static gboolean | |
221 play_file_nas(const char *filename) | |
222 { | |
223 AuServer *nas_serv; | |
224 gboolean ret = FALSE; | |
225 | |
226 if((nas_serv = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL))) { | |
227 ret = AuSoundPlaySynchronousFromFile(nas_serv, filename, 100); | |
228 AuCloseServer(nas_serv); | |
229 } | |
230 | |
231 return ret; | |
232 } | |
233 | |
234 #endif /* USE_NAS_AUDIO */ | |
235 | |
10074 | 236 #if defined(USE_NAS_AUDIO) || defined(USE_AO) |
10322 | 237 static gboolean |
238 expire_old_child(gpointer data) | |
10074 | 239 { |
240 int ret; | |
241 pid_t pid = GPOINTER_TO_INT(data); | |
242 | |
243 ret = waitpid(pid, NULL, WNOHANG | WUNTRACED); | |
244 | |
245 if(ret == 0) { | |
246 if(kill(pid, SIGKILL) < 0) | |
10322 | 247 gaim_debug_error("gtksound", "Killing process %d failed (%s)\n", |
248 pid, strerror(errno)); | |
10074 | 249 } |
250 | |
251 return FALSE; /* do not run again */ | |
252 } | |
253 #endif | |
254 | |
10322 | 255 static void |
256 gaim_gtk_sound_play_file(const char *filename) | |
5684 | 257 { |
258 const char *method; | |
259 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | |
260 pid_t pid; | |
261 #ifdef USE_AO | |
262 AFfilehandle file; | |
263 #endif | |
264 #endif | |
265 | |
6199 | 266 if (!sound_initialized) |
267 gaim_prefs_trigger_callback("/gaim/gtk/sound/method"); | |
268 | |
10074 | 269 if (gaim_prefs_get_bool("/gaim/gtk/sound/mute")) |
5684 | 270 return; |
271 | |
272 method = gaim_prefs_get_string("/gaim/gtk/sound/method"); | |
273 | |
10074 | 274 if (!strcmp(method, "none")) { |
275 return; | |
276 } else if (!strcmp(method, "beep")) { | |
5684 | 277 gdk_beep(); |
278 return; | |
279 } | |
280 | |
281 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
282 char *tmp = g_strdup_printf(_("Unable to play sound because the chosen file (%s) does not exist."), filename); | |
283 gaim_notify_error(NULL, NULL, tmp, NULL); | |
284 g_free(tmp); | |
285 return; | |
286 } | |
287 | |
288 #ifndef _WIN32 | |
289 if (!strcmp(method, "custom")) { | |
290 const char *sound_cmd; | |
291 char *command; | |
292 GError *error = NULL; | |
293 | |
294 sound_cmd = gaim_prefs_get_string("/gaim/gtk/sound/command"); | |
295 | |
296 if (!sound_cmd || *sound_cmd == '\0') { | |
297 gaim_notify_error(NULL, NULL, | |
298 _("Unable to play sound because the " | |
299 "'Command' sound method has been chosen, " | |
300 "but no command has been set."), NULL); | |
301 return; | |
302 } | |
303 | |
7464 | 304 if(strstr(sound_cmd, "%s")) |
305 command = gaim_strreplace(sound_cmd, "%s", filename); | |
306 else | |
307 command = g_strdup_printf("%s %s", sound_cmd, filename); | |
5684 | 308 |
309 if(!g_spawn_command_line_async(command, &error)) { | |
310 char *tmp = g_strdup_printf(_("Unable to play sound because the configured sound command could not be launched: %s"), error->message); | |
311 gaim_notify_error(NULL, NULL, tmp, NULL); | |
312 g_free(tmp); | |
313 g_error_free(error); | |
314 } | |
315 | |
316 g_free(command); | |
317 return; | |
318 } | |
319 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | |
320 pid = fork(); | |
321 if (pid < 0) | |
322 return; | |
323 else if (pid == 0) { | |
324 #ifdef USE_NAS_AUDIO | |
325 if (!strcmp(method, "nas")) { | |
326 if (play_file_nas(filename)) | |
327 _exit(0); | |
328 } | |
329 #endif /* USE_NAS_AUDIO */ | |
330 | |
331 #ifdef USE_AO | |
332 file = afOpenFile(filename, "rb", NULL); | |
333 if(file) { | |
334 ao_device *device; | |
335 ao_sample_format format; | |
336 int in_fmt; | |
337 int bytes_per_frame; | |
338 | |
339 format.rate = afGetRate(file, AF_DEFAULT_TRACK); | |
340 format.channels = afGetChannels(file, AF_DEFAULT_TRACK); | |
341 afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt, | |
342 &format.bits); | |
343 | |
344 /* XXX: libao doesn't seem to like 8-bit sounds, so we'll | |
345 * let libaudiofile make them a bit better for us */ | |
346 if(format.bits == 8) | |
347 format.bits = 16; | |
348 | |
349 afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, | |
350 AF_SAMPFMT_TWOSCOMP, format.bits); | |
351 | |
352 #if __BYTE_ORDER == __BIG_ENDIAN | |
353 format.byte_format = AO_FMT_BIG; | |
354 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
355 AF_BYTEORDER_BIGENDIAN); | |
356 #elif __BYTE_ORDER == __LITTLE_ENDIAN | |
357 format.byte_format = AO_FMT_LITTLE; | |
358 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
359 AF_BYTEORDER_LITTLEENDIAN); | |
360 #endif | |
361 | |
362 bytes_per_frame = format.bits * format.channels / 8; | |
363 | |
364 device = ao_open_live(ao_driver, &format, NULL); | |
365 | |
366 if(device) { | |
367 int frames_read; | |
368 char buf[4096]; | |
369 int buf_frames = sizeof(buf) / bytes_per_frame; | |
370 | |
371 while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK, | |
372 buf, buf_frames))) { | |
373 if(!ao_play(device, buf, frames_read * bytes_per_frame)) | |
374 break; | |
375 } | |
376 ao_close(device); | |
377 } | |
378 afCloseFile(file); | |
379 } | |
380 ao_shutdown(); | |
381 #endif /* USE_AO */ | |
382 _exit(0); | |
10074 | 383 } else { |
384 gaim_timeout_add(PLAY_SOUND_TIMEOUT, expire_old_child, GINT_TO_POINTER(pid)); | |
5684 | 385 } |
386 #else /* USE_NAS_AUDIO || USE_AO */ | |
387 gdk_beep(); | |
388 return; | |
389 #endif /* USE_NAS_AUDIO || USE_AO */ | |
390 #else /* _WIN32 */ | |
10322 | 391 gaim_debug_info("sound", "Playing %s\n", filename); |
5684 | 392 |
393 if (!PlaySound(filename, 0, SND_ASYNC | SND_FILENAME)) | |
10322 | 394 gaim_debug_error("sound", "Error playing sound.\n"); |
5684 | 395 #endif /* _WIN32 */ |
396 } | |
397 | |
10322 | 398 static void |
399 gaim_gtk_sound_play_event(GaimSoundEventID event) | |
5684 | 400 { |
401 char *enable_pref; | |
402 char *file_pref; | |
403 | |
404 if ((event == GAIM_SOUND_BUDDY_ARRIVE) && mute_login_sounds) | |
405 return; | |
406 | |
407 if (event >= GAIM_NUM_SOUNDS) { | |
10322 | 408 gaim_debug_error("sound", "got request for unknown sound: %d\n", event); |
5684 | 409 return; |
410 } | |
411 | |
412 enable_pref = g_strdup_printf("/gaim/gtk/sound/enabled/%s", | |
413 sounds[event].pref); | |
414 file_pref = g_strdup_printf("/gaim/gtk/sound/file/%s", sounds[event].pref); | |
415 | |
416 /* check NULL for sounds that don't have an option, ie buddy pounce */ | |
417 if (gaim_prefs_get_bool(enable_pref)) { | |
418 char *filename = g_strdup(gaim_prefs_get_string(file_pref)); | |
419 if(!filename || !strlen(filename)) { | |
420 if(filename) g_free(filename); | |
421 filename = g_build_filename(DATADIR, "sounds", "gaim", sounds[event].def, NULL); | |
422 } | |
423 | |
424 gaim_sound_play_file(filename); | |
425 g_free(filename); | |
426 } | |
427 | |
428 g_free(enable_pref); | |
429 g_free(file_pref); | |
430 } | |
431 | |
432 static GaimSoundUiOps sound_ui_ops = | |
433 { | |
434 gaim_gtk_sound_init, | |
10322 | 435 gaim_gtk_sound_uninit, |
5684 | 436 gaim_gtk_sound_play_file, |
437 gaim_gtk_sound_play_event | |
438 }; | |
439 | |
7035
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
440 GaimSoundUiOps * |
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
441 gaim_gtk_sound_get_ui_ops(void) |
5684 | 442 { |
443 return &sound_ui_ops; | |
444 } |