Mercurial > pidgin
annotate src/gtksound.c @ 7864:dc80d4e5c3b0
[gaim-migrate @ 8518]
"Attached is a patch I wrote last night while trying to play with
docklet.c - it turns out that one of the signals doesn't have the right
parameter list (probably after Christian changed the signals some time).
It has been tested, rather simply with the fact that a debug statement
was not reached before, and is now, following the signal specs here:
http://gaim.sourceforge.net/api/conversation-signals.html#received-im-msg
I don't know if this needs to go through Robot101 (haven't seen him
terribly active of late), and if it does, I'll gladly relay it to him.
And yeah, I guess this was all inspired by my away msg at the time:
[:-P]
Well, I'm not that tired right now, and I think I'm going to work some
Merlot and coffee off with some coding and Oggs...
Oh yeah, and while I'm rambling about stuff irrelevant to the actual
code, I somehow dedicate this patch to the wonderful person for whom I
would like to be visually aware of their incoming messages..." --John B.
Silvestri
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Sun, 14 Dec 2003 17:04:00 +0000 |
parents | dedbfdc7ce65 |
children | fa6395637e2c |
rev | line source |
---|---|
5684 | 1 /* |
2 * gaim | |
3 * | |
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
5 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 * | |
21 */ | |
6371
8f94cce8faa5
[gaim-migrate @ 6876]
Christian Hammond <chipx86@chipx86.com>
parents:
6199
diff
changeset
|
22 #include "gtkinternal.h" |
5684 | 23 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
24 #ifdef _WIN32 |
5684 | 25 #include <windows.h> |
26 #include <mmsystem.h> | |
27 #endif | |
28 | |
29 #ifdef USE_AO | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
30 # include <ao/ao.h> |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
31 # include <audiofile.h> |
5684 | 32 #endif /* USE_AO */ |
33 | |
34 #ifdef USE_NAS_AUDIO | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
35 # include <audio/audiolib.h> |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
36 # include <audio/soundlib.h> |
5684 | 37 #endif /* USE_NAS_AUDIO */ |
38 | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
39 #include "debug.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
40 #include "notify.h" |
5684 | 41 #include "prefs.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
42 #include "sound.h" |
7465 | 43 #include "util.h" |
5684 | 44 |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5794
diff
changeset
|
45 #include "gtksound.h" |
5684 | 46 |
47 | |
48 struct gaim_sound_event { | |
49 char *label; | |
50 char *pref; | |
51 char *def; | |
52 }; | |
53 | |
54 | |
55 | |
56 static gboolean mute_login_sounds = FALSE; | |
57 static gboolean mute_sounds = FALSE; | |
6199 | 58 static gboolean sound_initialized = FALSE; |
5684 | 59 |
60 static struct gaim_sound_event sounds[GAIM_NUM_SOUNDS] = { | |
61 {N_("Buddy logs in"), "login", "arrive.wav"}, | |
62 {N_("Buddy logs out"), "logout", "leave.wav"}, | |
63 {N_("Message received"), "im_recv", "receive.wav"}, | |
64 {N_("Message received begins conversation"), "first_im_recv", "receive.wav"}, | |
65 {N_("Message sent"), "send_im", "send.wav"}, | |
66 {N_("Person enters chat"), "join_chat", "arrive.wav"}, | |
67 {N_("Person leaves chat"), "left_chat", "leave.wav"}, | |
68 {N_("You talk in chat"), "send_chat_msg", "send.wav"}, | |
69 {N_("Others talk in chat"), "chat_msg_recv", "receive.wav"}, | |
70 /* this isn't a terminator, it's the buddy pounce default sound event ;-) */ | |
71 {NULL, "pounce_default", "redalert.wav"}, | |
72 {N_("Someone says your name in chat"), "nick_said", "redalert.wav"} | |
73 }; | |
74 | |
75 #ifdef USE_AO | |
76 static int ao_driver = -1; | |
77 #endif /* USE_AO */ | |
78 | |
5794
5e93fc46d1af
[gaim-migrate @ 6219]
Christian Hammond <chipx86@chipx86.com>
parents:
5684
diff
changeset
|
79 static void _pref_sound_method_changed(const char *name, GaimPrefType type, |
5684 | 80 gpointer val, gpointer data); |
81 | |
82 static void gaim_gtk_sound_init(void) | |
83 { | |
84 gaim_prefs_add_none("/gaim/gtk/sound"); | |
85 gaim_prefs_add_none("/gaim/gtk/sound/enabled"); | |
86 gaim_prefs_add_none("/gaim/gtk/sound/file"); | |
87 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/login", TRUE); | |
88 gaim_prefs_add_string("/gaim/gtk/sound/file/login", ""); | |
89 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/logout", TRUE); | |
90 gaim_prefs_add_string("/gaim/gtk/sound/file/logout", ""); | |
91 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/im_recv", TRUE); | |
92 gaim_prefs_add_string("/gaim/gtk/sound/file/im_recv", ""); | |
93 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/first_im_recv", FALSE); | |
94 gaim_prefs_add_string("/gaim/gtk/sound/file/first_im_recv", ""); | |
95 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_im", TRUE); | |
96 gaim_prefs_add_string("/gaim/gtk/sound/file/send_im", ""); | |
97 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/join_chat", FALSE); | |
98 gaim_prefs_add_string("/gaim/gtk/sound/file/join_chat", ""); | |
99 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/left_chat", FALSE); | |
100 gaim_prefs_add_string("/gaim/gtk/sound/file/left_chat", ""); | |
101 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/send_chat_msg", FALSE); | |
102 gaim_prefs_add_string("/gaim/gtk/sound/file/send_chat_msg", ""); | |
103 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/chat_msg_recv", FALSE); | |
104 gaim_prefs_add_string("/gaim/gtk/sound/file/chat_msg_recv", ""); | |
105 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/nick_said", FALSE); | |
106 gaim_prefs_add_string("/gaim/gtk/sound/file/nick_said", ""); | |
7460
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
107 gaim_prefs_add_bool("/gaim/gtk/sound/enabled/pounce_default", TRUE); |
3973a09525b3
[gaim-migrate @ 8073]
Christian Hammond <chipx86@chipx86.com>
parents:
7035
diff
changeset
|
108 gaim_prefs_add_string("/gaim/gtk/sound/file/pounce_default", ""); |
5684 | 109 gaim_prefs_add_bool("/gaim/gtk/sound/silent_signon", TRUE); |
110 gaim_prefs_add_string("/gaim/gtk/sound/command", ""); | |
111 gaim_prefs_add_string("/gaim/gtk/sound/method", "automatic"); | |
112 | |
113 #ifdef USE_AO | |
114 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
115 "Initializing sound output drivers.\n"); | |
116 ao_initialize(); | |
117 #endif /* USE_AO */ | |
118 | |
119 gaim_prefs_connect_callback("/gaim/gtk/sound/method", | |
5794
5e93fc46d1af
[gaim-migrate @ 6219]
Christian Hammond <chipx86@chipx86.com>
parents:
5684
diff
changeset
|
120 _pref_sound_method_changed, NULL); |
5684 | 121 } |
122 | |
123 | |
124 static void gaim_gtk_sound_shutdown(void) | |
125 { | |
126 #ifdef USE_AO | |
127 ao_shutdown(); | |
128 #endif | |
6199 | 129 sound_initialized = FALSE; |
5684 | 130 } |
131 | |
132 static void gaim_gtk_sound_play_file(const char *filename) | |
133 { | |
134 const char *method; | |
135 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | |
136 pid_t pid; | |
137 #ifdef USE_AO | |
138 AFfilehandle file; | |
139 #endif | |
140 #endif | |
141 | |
6199 | 142 if (!sound_initialized) |
143 gaim_prefs_trigger_callback("/gaim/gtk/sound/method"); | |
144 | |
5684 | 145 if (mute_sounds) |
146 return; | |
147 | |
148 method = gaim_prefs_get_string("/gaim/gtk/sound/method"); | |
149 | |
150 if (!strcmp(method, "beep")) { | |
151 gdk_beep(); | |
152 return; | |
153 } | |
154 | |
155 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
156 char *tmp = g_strdup_printf(_("Unable to play sound because the chosen file (%s) does not exist."), filename); | |
157 gaim_notify_error(NULL, NULL, tmp, NULL); | |
158 g_free(tmp); | |
159 return; | |
160 } | |
161 | |
162 #ifndef _WIN32 | |
163 if (!strcmp(method, "custom")) { | |
164 const char *sound_cmd; | |
165 char *command; | |
166 GError *error = NULL; | |
167 | |
168 sound_cmd = gaim_prefs_get_string("/gaim/gtk/sound/command"); | |
169 | |
170 if (!sound_cmd || *sound_cmd == '\0') { | |
171 gaim_notify_error(NULL, NULL, | |
172 _("Unable to play sound because the " | |
173 "'Command' sound method has been chosen, " | |
174 "but no command has been set."), NULL); | |
175 return; | |
176 } | |
177 | |
7464 | 178 if(strstr(sound_cmd, "%s")) |
179 command = gaim_strreplace(sound_cmd, "%s", filename); | |
180 else | |
181 command = g_strdup_printf("%s %s", sound_cmd, filename); | |
5684 | 182 |
183 if(!g_spawn_command_line_async(command, &error)) { | |
184 char *tmp = g_strdup_printf(_("Unable to play sound because the configured sound command could not be launched: %s"), error->message); | |
185 gaim_notify_error(NULL, NULL, tmp, NULL); | |
186 g_free(tmp); | |
187 g_error_free(error); | |
188 } | |
189 | |
190 g_free(command); | |
191 return; | |
192 } | |
193 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | |
194 pid = fork(); | |
195 if (pid < 0) | |
196 return; | |
197 else if (pid == 0) { | |
198 #ifdef USE_NAS_AUDIO | |
199 if (!strcmp(method, "nas")) { | |
200 if (play_file_nas(filename)) | |
201 _exit(0); | |
202 } | |
203 #endif /* USE_NAS_AUDIO */ | |
204 | |
205 #ifdef USE_AO | |
206 file = afOpenFile(filename, "rb", NULL); | |
207 if(file) { | |
208 ao_device *device; | |
209 ao_sample_format format; | |
210 int in_fmt; | |
211 int bytes_per_frame; | |
212 | |
213 format.rate = afGetRate(file, AF_DEFAULT_TRACK); | |
214 format.channels = afGetChannels(file, AF_DEFAULT_TRACK); | |
215 afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt, | |
216 &format.bits); | |
217 | |
218 /* XXX: libao doesn't seem to like 8-bit sounds, so we'll | |
219 * let libaudiofile make them a bit better for us */ | |
220 if(format.bits == 8) | |
221 format.bits = 16; | |
222 | |
223 afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, | |
224 AF_SAMPFMT_TWOSCOMP, format.bits); | |
225 | |
226 #if __BYTE_ORDER == __BIG_ENDIAN | |
227 format.byte_format = AO_FMT_BIG; | |
228 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
229 AF_BYTEORDER_BIGENDIAN); | |
230 #elif __BYTE_ORDER == __LITTLE_ENDIAN | |
231 format.byte_format = AO_FMT_LITTLE; | |
232 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
233 AF_BYTEORDER_LITTLEENDIAN); | |
234 #endif | |
235 | |
236 bytes_per_frame = format.bits * format.channels / 8; | |
237 | |
238 device = ao_open_live(ao_driver, &format, NULL); | |
239 | |
240 if(device) { | |
241 int frames_read; | |
242 char buf[4096]; | |
243 int buf_frames = sizeof(buf) / bytes_per_frame; | |
244 | |
245 while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK, | |
246 buf, buf_frames))) { | |
247 if(!ao_play(device, buf, frames_read * bytes_per_frame)) | |
248 break; | |
249 } | |
250 ao_close(device); | |
251 } | |
252 afCloseFile(file); | |
253 } | |
254 ao_shutdown(); | |
255 #endif /* USE_AO */ | |
256 _exit(0); | |
257 } | |
258 #else /* USE_NAS_AUDIO || USE_AO */ | |
259 gdk_beep(); | |
260 return; | |
261 #endif /* USE_NAS_AUDIO || USE_AO */ | |
262 #else /* _WIN32 */ | |
263 gaim_debug(GAIM_DEBUG_INFO, "sound", "Playing %s\n", filename); | |
264 | |
265 if (!PlaySound(filename, 0, SND_ASYNC | SND_FILENAME)) | |
266 gaim_debug(GAIM_DEBUG_ERROR, "sound", "Error playing sound.\n"); | |
267 #endif /* _WIN32 */ | |
268 } | |
269 | |
270 static void gaim_gtk_sound_play_event(GaimSoundEventID event) | |
271 { | |
272 char *enable_pref; | |
273 char *file_pref; | |
274 | |
275 if ((event == GAIM_SOUND_BUDDY_ARRIVE) && mute_login_sounds) | |
276 return; | |
277 | |
278 if (event >= GAIM_NUM_SOUNDS) { | |
279 gaim_debug(GAIM_DEBUG_MISC, "sound", | |
280 "got request for unknown sound: %d\n", event); | |
281 return; | |
282 } | |
283 | |
284 enable_pref = g_strdup_printf("/gaim/gtk/sound/enabled/%s", | |
285 sounds[event].pref); | |
286 file_pref = g_strdup_printf("/gaim/gtk/sound/file/%s", sounds[event].pref); | |
287 | |
288 /* check NULL for sounds that don't have an option, ie buddy pounce */ | |
289 if (gaim_prefs_get_bool(enable_pref)) { | |
290 char *filename = g_strdup(gaim_prefs_get_string(file_pref)); | |
291 if(!filename || !strlen(filename)) { | |
292 if(filename) g_free(filename); | |
293 filename = g_build_filename(DATADIR, "sounds", "gaim", sounds[event].def, NULL); | |
294 } | |
295 | |
296 gaim_sound_play_file(filename); | |
297 g_free(filename); | |
298 } | |
299 | |
300 g_free(enable_pref); | |
301 g_free(file_pref); | |
302 } | |
303 | |
304 static GaimSoundUiOps sound_ui_ops = | |
305 { | |
306 gaim_gtk_sound_init, | |
307 gaim_gtk_sound_shutdown, | |
308 gaim_gtk_sound_play_file, | |
309 gaim_gtk_sound_play_event | |
310 }; | |
311 | |
7035
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
312 GaimSoundUiOps * |
feb3d21a7794
[gaim-migrate @ 7598]
Christian Hammond <chipx86@chipx86.com>
parents:
6778
diff
changeset
|
313 gaim_gtk_sound_get_ui_ops(void) |
5684 | 314 { |
315 return &sound_ui_ops; | |
316 } | |
317 | |
318 | |
5794
5e93fc46d1af
[gaim-migrate @ 6219]
Christian Hammond <chipx86@chipx86.com>
parents:
5684
diff
changeset
|
319 static void _pref_sound_method_changed(const char *name, GaimPrefType type, |
5684 | 320 gpointer val, gpointer data) { |
6778 | 321 if(type != GAIM_PREF_STRING || strcmp(name, "/gaim/gtk/sound/method")) |
322 return; | |
323 | |
6199 | 324 sound_initialized = TRUE; |
325 | |
5684 | 326 #ifdef USE_AO |
327 ao_driver = -1; | |
328 | |
329 if(!strcmp(val, "esd")) | |
330 ao_driver = ao_driver_id("esd"); | |
331 else if(!strcmp(val, "arts")) | |
332 ao_driver = ao_driver_id("arts"); | |
333 else if(!strcmp(val, "automatic")) | |
334 ao_driver = ao_default_driver_id(); | |
335 | |
336 if(ao_driver != -1) { | |
337 ao_info *info = ao_driver_info(ao_driver); | |
338 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
339 "Sound output driver loaded: %s\n", info->name); | |
340 } | |
341 #endif /* USE_AO */ | |
342 #ifdef USE_NAS | |
343 if (!strcmp(val, "nas")) | |
344 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
345 "Sound output driver loaded: NAS output\n"); | |
346 #endif /* USE_NAS */ | |
347 } | |
348 | |
349 #ifdef USE_NAS_AUDIO | |
350 static gboolean play_file_nas(const char *filename) | |
351 { | |
352 AuServer *nas_serv; | |
353 gboolean ret = FALSE; | |
354 | |
355 if((nas_serv = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL))) { | |
356 ret = AuSoundPlaySynchronousFromFile(nas_serv, filename, 100); | |
357 AuCloseServer(nas_serv); | |
358 } | |
359 | |
360 return ret; | |
361 } | |
362 | |
363 #endif /* USE_NAS_AUDIO */ | |
364 | |
365 void gaim_gtk_sound_set_mute(gboolean mute) | |
366 { | |
367 mute_sounds = mute; | |
368 } | |
369 | |
370 gboolean gaim_gtk_sound_get_mute() | |
371 { | |
372 return mute_sounds; | |
373 } | |
374 | |
375 void gaim_gtk_sound_set_login_mute(gboolean mute) | |
376 { | |
377 mute_login_sounds = mute; | |
378 } | |
379 | |
380 const char *gaim_gtk_sound_get_event_option(GaimSoundEventID event) | |
381 { | |
382 if(event >= GAIM_NUM_SOUNDS) | |
383 return 0; | |
384 | |
385 return sounds[event].pref; | |
386 } | |
387 | |
388 char *gaim_gtk_sound_get_event_label(GaimSoundEventID event) | |
389 { | |
390 if(event >= GAIM_NUM_SOUNDS) | |
391 return NULL; | |
392 | |
393 return sounds[event].label; | |
394 } | |
395 |