Mercurial > pidgin.yaz
comparison src/sound.c @ 5684:b61520e71679
[gaim-migrate @ 6104]
sound is now really core/ui split.
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Tue, 03 Jun 2003 03:33:20 +0000 |
parents | 9cd94a5bec8e |
children | 059d95c67cda |
comparison
equal
deleted
inserted
replaced
5683:9befba33f7c8 | 5684:b61520e71679 |
---|---|
1 /* | 1 /* |
2 * gaim | 2 * gaim |
3 * | 3 * |
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
5 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> | 4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> |
6 * | 5 * |
7 * This program is free software; you can redistribute it and/or modify | 6 * 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 | 7 * 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 | 8 * the Free Software Foundation; either version 2 of the License, or |
21 */ | 20 */ |
22 | 21 |
23 #ifdef HAVE_CONFIG_H | 22 #ifdef HAVE_CONFIG_H |
24 #include <config.h> | 23 #include <config.h> |
25 #endif | 24 #endif |
26 #include <stdio.h> | |
27 #include <stdlib.h> | |
28 #include <string.h> | |
29 | 25 |
30 #ifndef _WIN32 | |
31 #include <unistd.h> | |
32 #else | |
33 #include <windows.h> | |
34 #include <mmsystem.h> | |
35 #endif | |
36 | |
37 #ifdef HAVE_ENDIAN_H | |
38 #include <endian.h> | |
39 #endif | |
40 | |
41 #ifdef USE_AO | |
42 #include <ao/ao.h> | |
43 #include <audiofile.h> | |
44 #endif /* USE_AO */ | |
45 #ifdef USE_NAS_AUDIO | |
46 #include <audio/audiolib.h> | |
47 #include <audio/soundlib.h> | |
48 #endif /* USE_NAS_AUDIO */ | |
49 | |
50 #include "gaim.h" | |
51 #include "sound.h" | 26 #include "sound.h" |
52 #include "notify.h" | |
53 #include "prefs.h" | 27 #include "prefs.h" |
28 #include "gaim.h" /* XXX: this goes away when away messages become sane */ | |
54 | 29 |
55 #ifdef _WIN32 | 30 #ifdef _WIN32 |
56 #include "win32dep.h" | 31 #include "win32dep.h" |
57 #endif | 32 #endif |
58 | 33 |
59 struct gaim_sound_event { | 34 static GaimSoundUiOps *sound_ui_ops = NULL; |
60 char *label; | |
61 char *pref; | |
62 char *def; | |
63 }; | |
64 | 35 |
65 #ifdef USE_AO | 36 void gaim_set_sound_ui_ops(GaimSoundUiOps *ops) |
66 static gboolean ao_initialized=FALSE; | |
67 static int ao_driver = -1; | |
68 #endif /* USE_AO */ | |
69 | |
70 | |
71 static gboolean mute_login_sounds = FALSE; | |
72 static gboolean mute_sounds = FALSE; | |
73 static char *sound_cmd = NULL; | |
74 | |
75 /* description, option bit, default sound file * | |
76 * set the option bit to 0 to have it not display in prefs * | |
77 * the order here has to match the defines in gaim.h. * | |
78 * -Robot101 */ | |
79 static struct gaim_sound_event sounds[GAIM_NUM_SOUNDS] = { | |
80 {N_("Buddy logs in"), "/gaim/gtk/sound/login", "arrive.wav"}, | |
81 {N_("Buddy logs out"), "/gaim/gtk/sound/logout", "leave.wav"}, | |
82 {N_("Message received"), "/gaim/gtk/sound/im_recv", "receive.wav"}, | |
83 {N_("Message received begins conversation"), "/gaim/gtk/sound/first_im_recv", "receive.wav"}, | |
84 {N_("Message sent"), "/gaim/gtk/sound/send_im", "send.wav"}, | |
85 {N_("Person enters chat"), "/gaim/gtk/sound/join_chat", "arrive.wav"}, | |
86 {N_("Person leaves chat"), "/gaim/gtk/sound/left_chat", "leave.wav"}, | |
87 {N_("You talk in chat"), "/gaim/gtk/sound/send_chat_msg", "send.wav"}, | |
88 {N_("Others talk in chat"), "/gaim/gtk/sound/chat_msg_recv", "receive.wav"}, | |
89 /* this isn't a terminator, it's the buddy pounce default sound event ;-) */ | |
90 {NULL, 0, "redalert.wav"}, | |
91 {N_("Someone says your name in chat"), "/gaim/gtk/sound/nick_said", "redalert.wav"} | |
92 }; | |
93 | |
94 static char *sound_file[GAIM_NUM_SOUNDS]; | |
95 | |
96 | |
97 #ifdef USE_AO | |
98 static void check_ao_init() | |
99 { | 37 { |
100 if(!ao_initialized) { | 38 if(sound_ui_ops && sound_ui_ops->shutdown) |
101 gaim_debug(GAIM_DEBUG_INFO, "sound", | 39 sound_ui_ops->shutdown(); |
102 "Initializing sound output drivers.\n"); | 40 sound_ui_ops = ops; |
103 ao_initialize(); | 41 if(sound_ui_ops && sound_ui_ops->init) |
104 ao_initialized = TRUE; | 42 sound_ui_ops->init(); |
105 } | |
106 } | |
107 #endif /* USE_AO */ | |
108 | |
109 void gaim_sound_change_output_method() { | |
110 #ifdef USE_AO | |
111 ao_driver = -1; | |
112 | |
113 if (gaim_prefs_get_bool("/core/sound/use_esd") || | |
114 gaim_prefs_get_bool("/core/sound/use_arts") || | |
115 gaim_prefs_get_bool("/core/sound/use_sys_default")) { | |
116 | |
117 check_ao_init(); | |
118 | |
119 if (ao_driver == -1 && gaim_prefs_get_bool("/core/sound/use_esd")) | |
120 ao_driver = ao_driver_id("esd"); | |
121 | |
122 if (ao_driver == -1 && gaim_prefs_get_bool("/core/sound/use_arts")) | |
123 ao_driver = ao_driver_id("arts"); | |
124 | |
125 if (ao_driver == -1) | |
126 ao_driver = ao_default_driver_id(); | |
127 } | |
128 | |
129 if(ao_driver != -1) { | |
130 ao_info *info = ao_driver_info(ao_driver); | |
131 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
132 "Sound output driver loaded: %s\n", info->name); | |
133 } | |
134 #endif /* USE_AO */ | |
135 #ifdef USE_NAS | |
136 if (gaim_prefs_get_bool("/core/sound/use_nas")) | |
137 gaim_debug(GAIM_DEBUG_INFO, "sound", | |
138 "Sound output driver loaded: NAS output\n"); | |
139 #endif /* USE_NAS */ | |
140 } | 43 } |
141 | 44 |
142 void gaim_sound_quit() | 45 GaimSoundUiOps *gaim_get_sound_ui_ops(void) |
143 { | 46 { |
144 #ifdef USE_AO | 47 return sound_ui_ops; |
145 if(ao_initialized) | |
146 ao_shutdown(); | |
147 #endif | |
148 } | 48 } |
149 | 49 |
150 | 50 void gaim_sound_init() |
151 #ifdef USE_NAS_AUDIO | |
152 static gboolean play_file_nas(const char *filename) | |
153 { | 51 { |
154 AuServer *nas_serv; | 52 gaim_prefs_add_none("/core/sound"); |
155 gboolean ret = FALSE; | 53 gaim_prefs_add_bool("/core/sound/while_away", FALSE); |
156 | |
157 if((nas_serv = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL))) { | |
158 ret = AuSoundPlaySynchronousFromFile(nas_serv, filename, 100); | |
159 AuCloseServer(nas_serv); | |
160 } | |
161 | |
162 return ret; | |
163 } | 54 } |
164 | 55 |
165 #endif /* USE_NAS_AUDIO */ | 56 void gaim_sound_shutdown() |
57 { | |
58 if(sound_ui_ops && sound_ui_ops->shutdown) | |
59 sound_ui_ops->shutdown(); | |
60 } | |
166 | 61 |
167 void gaim_sound_play_file(char *filename) | 62 void gaim_sound_play_file(const char *filename) |
168 { | 63 { |
169 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | 64 if(awaymessage && !gaim_prefs_get_bool("/core/sound/while_away")) |
170 pid_t pid; | |
171 #ifdef USE_AO | |
172 AFfilehandle file; | |
173 #endif | |
174 #endif | |
175 | |
176 if (mute_sounds) | |
177 return; | 65 return; |
178 | 66 |
179 if (awaymessage && !gaim_prefs_get_bool("/core/sound/while_away")) | 67 if(sound_ui_ops && sound_ui_ops->play_file) |
180 return; /* check here in case a buddy pounce plays a file while away */ | 68 sound_ui_ops->play_file(filename); |
181 | |
182 if (gaim_prefs_get_bool("/core/sound/use_beep")) { | |
183 gdk_beep(); | |
184 return; | |
185 } | |
186 | |
187 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
188 char *tmp = g_strdup_printf(_("Unable to play sound because the chosen file (%s) does not exist."), filename); | |
189 gaim_notify_error(NULL, NULL, tmp, NULL); | |
190 g_free(tmp); | |
191 return; | |
192 } | |
193 | |
194 #ifndef _WIN32 | |
195 if (gaim_prefs_get_bool("/core/sound/use_custom")) { | |
196 const char *sound_cmd; | |
197 char *command; | |
198 GError *error = NULL; | |
199 | |
200 sound_cmd = gaim_prefs_get_string("/core/sound/command"); | |
201 | |
202 if (!sound_cmd || *sound_cmd == '\0') { | |
203 gaim_notify_error(NULL, NULL, | |
204 _("Unable to play sound because the " | |
205 "'Command' sound method has been chosen, " | |
206 "but no command has been set."), NULL); | |
207 return; | |
208 } | |
209 | |
210 command = g_strdup_printf(sound_cmd, filename); | |
211 | |
212 if(!g_spawn_command_line_async(command, &error)) { | |
213 char *tmp = g_strdup_printf(_("Unable to play sound because the configured sound command could not be launched: %s"), error->message); | |
214 gaim_notify_error(NULL, NULL, tmp, NULL); | |
215 g_free(tmp); | |
216 g_error_free(error); | |
217 } | |
218 | |
219 g_free(command); | |
220 return; | |
221 } | |
222 #if defined(USE_NAS_AUDIO) || defined(USE_AO) | |
223 pid = fork(); | |
224 if (pid < 0) | |
225 return; | |
226 else if (pid == 0) { | |
227 #ifdef USE_NAS_AUDIO | |
228 if (gaim_prefs_get_bool("/core/sound/use_nas")) { | |
229 if (play_file_nas(filename)) | |
230 _exit(0); | |
231 } | |
232 #endif /* USE_NAS_AUDIO */ | |
233 | |
234 #ifdef USE_AO | |
235 file = afOpenFile(filename, "rb", NULL); | |
236 if(file) { | |
237 ao_device *device; | |
238 ao_sample_format format; | |
239 int in_fmt; | |
240 int bytes_per_frame; | |
241 | |
242 format.rate = afGetRate(file, AF_DEFAULT_TRACK); | |
243 format.channels = afGetChannels(file, AF_DEFAULT_TRACK); | |
244 afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt, | |
245 &format.bits); | |
246 | |
247 /* XXX: libao doesn't seem to like 8-bit sounds, so we'll | |
248 * let libaudiofile make them a bit better for us */ | |
249 if(format.bits == 8) | |
250 format.bits = 16; | |
251 | |
252 afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, | |
253 AF_SAMPFMT_TWOSCOMP, format.bits); | |
254 | |
255 #if __BYTE_ORDER == __BIG_ENDIAN | |
256 format.byte_format = AO_FMT_BIG; | |
257 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
258 AF_BYTEORDER_BIGENDIAN); | |
259 #elif __BYTE_ORDER == __LITTLE_ENDIAN | |
260 format.byte_format = AO_FMT_LITTLE; | |
261 afSetVirtualByteOrder(file, AF_DEFAULT_TRACK, | |
262 AF_BYTEORDER_LITTLEENDIAN); | |
263 #endif | |
264 | |
265 bytes_per_frame = format.bits * format.channels / 8; | |
266 | |
267 device = ao_open_live(ao_driver, &format, NULL); | |
268 | |
269 if(device) { | |
270 int frames_read; | |
271 char buf[4096]; | |
272 int buf_frames = sizeof(buf) / bytes_per_frame; | |
273 | |
274 while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK, | |
275 buf, buf_frames))) { | |
276 if(!ao_play(device, buf, frames_read * bytes_per_frame)) | |
277 break; | |
278 } | |
279 ao_close(device); | |
280 } | |
281 afCloseFile(file); | |
282 } | |
283 ao_shutdown(); | |
284 #endif /* USE_AO */ | |
285 _exit(0); | |
286 } | |
287 #else /* USE_NAS_AUDIO || USE_AO */ | |
288 gdk_beep(); | |
289 return; | |
290 #endif /* USE_NAS_AUDIO || USE_AO */ | |
291 #else /* _WIN32 */ | |
292 gaim_debug(GAIM_DEBUG_INFO, "sound", "Playing %s\n", filename); | |
293 | |
294 if (!PlaySound(filename, 0, SND_ASYNC | SND_FILENAME)) | |
295 gaim_debug(GAIM_DEBUG_ERROR, "sound", "Error playing sound.\n"); | |
296 #endif /* _WIN32 */ | |
297 } | 69 } |
298 | 70 |
299 void gaim_sound_play_event(GaimSoundEventID event) | 71 void gaim_sound_play_event(GaimSoundEventID event) |
300 { | 72 { |
301 if ((event == GAIM_SOUND_BUDDY_ARRIVE) && mute_login_sounds) | 73 if(awaymessage && !gaim_prefs_get_bool("/core/sound/while_away")) |
302 return; | 74 return; |
303 | 75 |
304 if (event >= GAIM_NUM_SOUNDS) { | 76 if(sound_ui_ops && sound_ui_ops->play_event) |
305 gaim_debug(GAIM_DEBUG_MISC, "sound", | 77 sound_ui_ops->play_event(event); |
306 "got request for unknown sound: %d\n", event); | |
307 return; | |
308 } | |
309 | |
310 /* check NULL for sounds that don't have an option, ie buddy pounce */ | |
311 if (sounds[event].pref == NULL || gaim_prefs_get_bool(sounds[event].pref)) { | |
312 if (sound_file[event]) { | |
313 gaim_sound_play_file(sound_file[event]); | |
314 } else { | |
315 gchar *filename = NULL; | |
316 | |
317 filename = g_build_filename(DATADIR, "sounds", "gaim", sounds[event].def, NULL); | |
318 gaim_sound_play_file(filename); | |
319 g_free(filename); | |
320 } | |
321 } | |
322 } | 78 } |
323 | |
324 void gaim_sound_set_mute(gboolean mute) | |
325 { | |
326 mute_sounds = mute; | |
327 } | |
328 | |
329 gboolean gaim_sound_get_mute() | |
330 { | |
331 return mute_sounds; | |
332 } | |
333 | |
334 void gaim_sound_set_login_mute(gboolean mute) | |
335 { | |
336 mute_login_sounds = mute; | |
337 } | |
338 | |
339 void gaim_sound_set_event_file(GaimSoundEventID event, const char *filename) | |
340 { | |
341 if(event >= GAIM_NUM_SOUNDS) | |
342 return; | |
343 | |
344 if(sound_file[event]) | |
345 g_free(sound_file[event]); | |
346 | |
347 sound_file[event] = g_strdup(filename); | |
348 } | |
349 | |
350 | |
351 char *gaim_sound_get_event_file(GaimSoundEventID event) | |
352 { | |
353 if(event >= GAIM_NUM_SOUNDS) | |
354 return NULL; | |
355 | |
356 return sound_file[event]; | |
357 } | |
358 | |
359 const char *gaim_sound_get_event_option(GaimSoundEventID event) | |
360 { | |
361 if(event >= GAIM_NUM_SOUNDS) | |
362 return 0; | |
363 | |
364 return sounds[event].pref; | |
365 } | |
366 | |
367 char *gaim_sound_get_event_label(GaimSoundEventID event) | |
368 { | |
369 if(event >= GAIM_NUM_SOUNDS) | |
370 return NULL; | |
371 | |
372 return sounds[event].label; | |
373 } | |
374 | |
375 | |
376 void gaim_sound_set_command(const char *cmd) | |
377 { | |
378 if(sound_cmd) | |
379 g_free(sound_cmd); | |
380 if(strlen(cmd) > 0) | |
381 sound_cmd = g_strdup(cmd); | |
382 else | |
383 sound_cmd = NULL; | |
384 } | |
385 | |
386 char *gaim_sound_get_command() | |
387 { | |
388 return sound_cmd; | |
389 } | |
390 |