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