4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include <sys/types.h>
45 #include <audio/audiolib.h>
49 #include "sounds/BuddyArrive.h"
50 #include "sounds/BuddyLeave.h"
51 #include "sounds/Send.h"
52 #include "sounds/Receive.h"
53 #include "sounds/RedAlert.h"
55 static int check_dev(char *dev
)
58 uid_t user
= getuid();
59 gid_t group
= getgid(), other_groups
[32];
62 if ((numgroups
= getgroups(32, other_groups
)) == -1)
64 if (stat(dev
, &stat_buf
))
66 if (user
== stat_buf
.st_uid
&& stat_buf
.st_mode
& S_IWUSR
)
68 if (stat_buf
.st_mode
& S_IWGRP
) {
69 if (group
== stat_buf
.st_gid
)
71 for (i
= 0; i
< numgroups
; i
++)
72 if (other_groups
[i
] == stat_buf
.st_gid
)
75 if (stat_buf
.st_mode
& S_IWOTH
)
81 static void play_audio(unsigned char *data
, int size
)
85 fd
= open("/dev/audio", O_WRONLY
| O_EXCL
| O_NDELAY
);
88 write(fd
, data
, size
);
92 static void play_audio_file(char *file
)
94 /* here we can assume that we can write to /dev/audio */
97 int fd
= open(file
, O_RDONLY
);
102 if (info
.st_size
< 24)
104 buf
= malloc(info
.st_size
+ 1);
106 read(fd
, buf
, info
.st_size
- 24);
109 fd
= open("/dev/audio", O_WRONLY
| O_EXCL
| O_NDELAY
);
114 write(fd
, buf
, info
.st_size
- 24);
119 static int can_play_audio()
121 return check_dev("/dev/audio");
125 #if defined(ESD_SOUND) || defined(ARTSC_SOUND)
128 ** This routine converts from ulaw to 16 bit linear.
130 ** Craig Reese: IDA/Supercomputing Research Center
134 ** 1) CCITT Recommendation G.711 (very difficult to follow)
135 ** 2) MIL-STD-188-113,"Interoperability and Performance Standards
136 ** for Analog-to_Digital Conversion Techniques,"
139 ** Input: 8 bit ulaw sample
140 ** Output: signed 16 bit linear sample
141 ** Z-note -- this is from libaudiofile. Thanks guys!
144 static int _af_ulaw2linear(unsigned char ulawbyte
)
146 static int exp_lut
[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
147 int sign
, exponent
, mantissa
, sample
;
149 ulawbyte
= ~ulawbyte
;
150 sign
= (ulawbyte
& 0x80);
151 exponent
= (ulawbyte
>> 4) & 0x07;
152 mantissa
= ulawbyte
& 0x0F;
153 sample
= exp_lut
[exponent
] + (mantissa
<< (exponent
+ 3));
166 static int play_esd(unsigned char *data
, int size
)
171 lineardata
= g_malloc(size
* 2);
173 for (i
= 0; i
< size
; i
++)
174 lineardata
[i
] = _af_ulaw2linear(data
[i
]);
176 write(esd_fd
, lineardata
, size
* 2);
185 static int can_play_esd()
187 esd_format_t format
= ESD_BITS16
| ESD_STREAM
| ESD_PLAY
| ESD_MONO
;
189 esd_fd
= esd_play_stream(format
, 8012, NULL
, "gaim");
202 static int play_artsc(unsigned char *data
, int size
)
204 arts_stream_t stream
;
210 lineardata
= g_malloc(size
* 2);
212 for (i
= 0; i
< size
; i
++) {
213 lineardata
[i
] = _af_ulaw2linear(data
[i
]);
216 stream
= arts_play_stream(8012, 16, 1, "gaim");
218 error
= arts_write(stream
, lineardata
, size
);
223 arts_close_stream(stream
);
232 static int can_play_artsc()
243 static int artsc_play_file(char *file
)
245 struct stat stat_buf
;
246 unsigned char *buf
= NULL
;
250 if (!can_play_artsc())
253 fd
= open(file
, O_RDONLY
);
257 if (fstat(fd
, &stat_buf
)) {
262 if (!stat_buf
.st_size
) {
267 buf
= g_malloc(stat_buf
.st_size
);
273 if (read(fd
, buf
, stat_buf
.st_size
) < 0) {
279 result
= play_artsc(buf
, stat_buf
.st_size
);
286 #endif /* ARTSC_SOUND */
290 char nas_server
[] = "localhost";
291 AuServer
*nas_serv
= NULL
;
293 static AuBool
NasEventHandler(AuServer
* aud
, AuEvent
* ev
, AuEventHandlerRec
* handler
)
295 AuElementNotifyEvent
*event
= (AuElementNotifyEvent
*) ev
;
297 if (ev
->type
== AuEventTypeElementNotify
) {
298 switch (event
->kind
) {
299 case AuElementNotifyKindState
:
300 switch (event
->cur_state
) {
311 static int play_nas(unsigned char *data
, int size
)
313 AuDeviceID device
= AuNone
;
315 AuElement elements
[3];
318 /* look for an output device */
319 for (i
= 0; i
< AuServerNumDevices(nas_serv
); i
++) {
320 if ((AuDeviceKind(AuServerDevice(nas_serv
, i
)) ==
321 AuComponentKindPhysicalOutput
) &&
322 AuDeviceNumTracks(AuServerDevice(nas_serv
, i
)) == 1) {
323 device
= AuDeviceIdentifier(AuServerDevice(nas_serv
, i
));
328 if (device
== AuNone
)
331 if (!(flow
= AuCreateFlow(nas_serv
, NULL
)))
335 AuMakeElementImportClient(&elements
[0], 8012, AuFormatULAW8
, 1, AuTrue
, size
, size
/ 2, 0, NULL
);
336 AuMakeElementExportDevice(&elements
[1], 0, device
, 8012, AuUnlimitedSamples
, 0, NULL
);
337 AuSetElements(nas_serv
, flow
, AuTrue
, 2, elements
, NULL
);
339 AuStartFlow(nas_serv
, flow
, NULL
);
341 AuWriteElement(nas_serv
, flow
, 0, size
, data
, AuTrue
, NULL
);
343 AuRegisterEventHandler(nas_serv
, AuEventHandlerIDMask
, 0, flow
, NasEventHandler
, NULL
);
346 AuHandleEvents(nas_serv
);
352 static int can_play_nas()
354 if ((nas_serv
= AuOpenServer(NULL
, 0, NULL
, 0, NULL
, NULL
)))
359 static int play_nas_file(char *file
)
361 struct stat stat_buf
;
364 int fd
= open(file
, O_RDONLY
);
371 if (stat(file
, &stat_buf
))
374 if (!stat_buf
.st_size
)
377 buf
= malloc(stat_buf
.st_size
);
378 read(fd
, buf
, stat_buf
.st_size
);
379 ret
= play_nas(buf
, stat_buf
.st_size
);
386 void play_file(char *filename
)
394 if (sound_options
& OPT_SOUND_BEEP
) {
406 if ((sound_options
& OPT_SOUND_CMD
) && sound_cmd
[0]) {
410 g_snprintf(command
, sizeof(command
), sound_cmd
, filename
);
416 execvp(args
[0], args
);
420 else if (sound_options
& OPT_SOUND_ESD
) {
421 if (esd_play_file(NULL
, filename
, 1))
427 else if (sound_options
& OPT_SOUND_ARTSC
) {
428 if (artsc_play_file(filename
))
434 else if (sound_options
& OPT_SOUND_NAS
) {
435 if (play_nas_file(filename
))
439 else if ((sound_options
& OPT_SOUND_NORMAL
) &&
441 play_audio_file(filename
);
447 g_timeout_add(100, clean_pid
, NULL
);
451 void play(unsigned char *data
, int size
)
459 if (sound_options
& OPT_SOUND_BEEP
) {
464 else if ((sound_options
& OPT_SOUND_CMD
) && sound_cmd
[0]) {
465 debug_printf("can't play internal sound with external command -- skipping\n");
477 /* ESD is our player of choice. Are we OK to
479 if (sound_options
& OPT_SOUND_ESD
) {
480 if (can_play_esd()) {
481 if (play_esd(data
, size
))
488 /* ArtsC is the new second choice. */
489 if (sound_options
& OPT_SOUND_ARTSC
) {
490 if (can_play_artsc()) {
491 if (play_artsc(data
, size
))
498 /* NAS is our second choice setup. */
499 if (sound_options
& OPT_SOUND_NAS
) {
500 if (can_play_nas()) {
501 if (play_nas(data
, size
))
507 /* Lastly, we can try just plain old /dev/audio */
508 if (sound_options
& OPT_SOUND_NORMAL
) {
509 if (can_play_audio()) {
510 play_audio(data
, size
);
517 g_timeout_add(100, clean_pid
, NULL
);
521 extern int logins_not_muted
;
523 void play_sound(int sound
)
526 if (awaymessage
&& !(sound_options
& OPT_SOUND_WHEN_AWAY
))
531 if ((sound_options
& OPT_SOUND_LOGIN
) && logins_not_muted
) {
532 if (sound_file
[BUDDY_ARRIVE
]) {
533 play_file(sound_file
[BUDDY_ARRIVE
]);
535 play(BuddyArrive
, sizeof(BuddyArrive
));
540 if (sound_options
& OPT_SOUND_LOGOUT
) {
541 if (sound_file
[BUDDY_LEAVE
]) {
542 play_file(sound_file
[BUDDY_LEAVE
]);
544 play(BuddyLeave
, sizeof(BuddyLeave
));
549 if (sound_options
& OPT_SOUND_FIRST_RCV
) {
550 if (sound_file
[FIRST_RECEIVE
]) {
551 play_file(sound_file
[FIRST_RECEIVE
]);
553 play(Receive
, sizeof(Receive
));
558 if (sound_options
& OPT_SOUND_RECV
) {
559 if (sound_file
[RECEIVE
]) {
560 play_file(sound_file
[RECEIVE
]);
562 play(Receive
, sizeof(Receive
));
567 if (sound_options
& OPT_SOUND_SEND
) {
568 if (sound_file
[SEND
]) {
569 play_file(sound_file
[SEND
]);
571 play(Send
, sizeof(Send
));
576 if (sound_options
& OPT_SOUND_CHAT_JOIN
) {
577 if (sound_file
[CHAT_JOIN
]) {
578 play_file(sound_file
[CHAT_JOIN
]);
580 play(BuddyArrive
, sizeof(BuddyArrive
));
585 if (sound_options
& OPT_SOUND_CHAT_PART
) {
586 if (sound_file
[CHAT_LEAVE
]) {
587 play_file(sound_file
[CHAT_LEAVE
]);
589 play(BuddyLeave
, sizeof(BuddyLeave
));
594 if (sound_options
& OPT_SOUND_CHAT_YOU_SAY
) {
595 if (sound_file
[CHAT_YOU_SAY
]) {
596 play_file(sound_file
[CHAT_YOU_SAY
]);
598 play(Send
, sizeof(Send
));
603 if (sound_options
& OPT_SOUND_CHAT_SAY
) {
604 if (sound_file
[CHAT_SAY
]) {
605 play_file(sound_file
[CHAT_SAY
]);
607 play(Receive
, sizeof(Receive
));
612 if (sound_file
[POUNCE_DEFAULT
]) {
613 play_file(sound_file
[POUNCE_DEFAULT
]);
615 play(RedAlert
, sizeof(RedAlert
));