Mercurial > pidgin.yaz
diff src/sound.c @ 4430:801830dec409
[gaim-migrate @ 4705]
robot101 gave me a bad patch
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Sun, 26 Jan 2003 20:43:25 +0000 |
parents | bf770f11132b |
children | 3196d9044a45 |
line wrap: on
line diff
--- a/src/sound.c Sun Jan 26 20:41:49 2003 +0000 +++ b/src/sound.c Sun Jan 26 20:43:25 2003 +0000 @@ -40,10 +40,17 @@ #include <sys/types.h> #include <sys/stat.h> -#ifdef USE_AO -#include <ao/ao.h> -#include <audiofile.h> -#endif /* USE_AO */ +#ifdef ESD_SOUND +#include <esd.h> +#endif + +#ifdef ARTSC_SOUND +#include <artsc.h> +#endif + +#ifdef NAS_SOUND +#include <audio/audiolib.h> +#endif #include "gaim.h" @@ -51,10 +58,6 @@ #include "win32dep.h" #endif -#ifdef USE_AO -static gboolean ao_initialized = FALSE; -#endif /* USE_AO */ - gboolean mute_sounds = 0; /* description, option bit, default sound file * @@ -76,109 +79,370 @@ {N_("Someone says your name in chat"), OPT_SOUND_CHAT_NICK, "redalert.wav"} }; +#ifndef _WIN32 +static int check_dev(char *dev) +{ + struct stat stat_buf; + uid_t user = getuid(); + gid_t group = getgid(), other_groups[32]; + int i, numgroups; + + if ((numgroups = getgroups(32, other_groups)) == -1) + return 0; + if (stat(dev, &stat_buf)) + return 0; + if (user == stat_buf.st_uid && stat_buf.st_mode & S_IWUSR) + return 1; + if (stat_buf.st_mode & S_IWGRP) { + if (group == stat_buf.st_gid) + return 1; + for (i = 0; i < numgroups; i++) + if (other_groups[i] == stat_buf.st_gid) + return 1; + } + if (stat_buf.st_mode & S_IWOTH) + return 1; + return 0; +} + +static void play_audio_file(char *file) +{ + /* here we can assume that we can write to /dev/audio */ + char *buf; + struct stat info; + int fd = open(file, O_RDONLY); + if (fd <= 0) { + return; + } + fstat(fd, &info); + if (info.st_size < 24) + return; + buf = malloc(info.st_size + 1); + read(fd, buf, 24); + read(fd, buf, info.st_size - 24); + close(fd); + + fd = open("/dev/audio", O_WRONLY | O_EXCL | O_NDELAY); + if (fd < 0) { + free(buf); + return; + } + write(fd, buf, info.st_size - 24); + free(buf); + close(fd); +} + +static int can_play_audio() +{ + return check_dev("/dev/audio"); +} + +#ifdef ESD_SOUND + +int esd_fd; + +static int can_play_esd() +{ + esd_format_t format = ESD_BITS16 | ESD_STREAM | ESD_PLAY | ESD_MONO; + + esd_fd = esd_play_stream(format, 8012, NULL, "gaim"); + + if (esd_fd < 0) { + return 0; + } + + return 1; +} + +#endif /* ESD_SOUND */ + +#ifdef ARTSC_SOUND + +/* +** This routine converts from ulaw to 16 bit linear. +** +** Craig Reese: IDA/Supercomputing Research Center +** 29 September 1989 +** +** References: +** 1) CCITT Recommendation G.711 (very difficult to follow) +** 2) MIL-STD-188-113,"Interoperability and Performance Standards +** for Analog-to_Digital Conversion Techniques," +** 17 February 1987 +** +** Input: 8 bit ulaw sample +** Output: signed 16 bit linear sample +** Z-note -- this is from libaudiofile. Thanks guys! +*/ + +static int _af_ulaw2linear(unsigned char ulawbyte) +{ + static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 }; + int sign, exponent, mantissa, sample; + + ulawbyte = ~ulawbyte; + sign = (ulawbyte & 0x80); + exponent = (ulawbyte >> 4) & 0x07; + mantissa = ulawbyte & 0x0F; + sample = exp_lut[exponent] + (mantissa << (exponent + 3)); + if (sign != 0) + sample = -sample; + + return (sample); +} + +static int play_artsc(unsigned char *data, int size) +{ + arts_stream_t stream; + guint16 *lineardata; + int result = 1; + int error; + int i; + + lineardata = g_malloc(size * 2); + + for (i = 0; i < size; i++) { + lineardata[i] = _af_ulaw2linear(data[i]); + } + + stream = arts_play_stream(8012, 16, 1, "gaim"); + + error = arts_write(stream, lineardata, size); + if (error < 0) { + result = 0; + } + + arts_close_stream(stream); + + g_free(lineardata); + + arts_free(); + + return result; +} + +static int can_play_artsc() +{ + int error; + + error = arts_init(); + if (error < 0) + return 0; + + return 1; +} + +static int artsc_play_file(char *file) +{ + struct stat stat_buf; + unsigned char *buf = NULL; + int result = 0; + int fd = -1; + + if (!can_play_artsc()) + return 0; + + fd = open(file, O_RDONLY); + if (fd < 0) + return 0; + + if (fstat(fd, &stat_buf)) { + close(fd); + return 0; + } + + if (!stat_buf.st_size) { + close(fd); + return 0; + } + + buf = g_malloc(stat_buf.st_size); + if (!buf) { + close(fd); + return 0; + } + + if (read(fd, buf, stat_buf.st_size) < 0) { + g_free(buf); + close(fd); + return 0; + } + + result = play_artsc(buf, stat_buf.st_size); + + g_free(buf); + close(fd); + return result; +} + +#endif /* ARTSC_SOUND */ + +#ifdef NAS_SOUND + +char nas_server[] = "localhost"; +AuServer *nas_serv = NULL; + +static AuBool NasEventHandler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * handler) +{ + AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev; + + if (ev->type == AuEventTypeElementNotify) { + switch (event->kind) { + case AuElementNotifyKindState: + switch (event->cur_state) { + case AuStateStop: + _exit(0); + } + break; + } + } + return AuTrue; +} + + +static int play_nas(unsigned char *data, int size) +{ + AuDeviceID device = AuNone; + AuFlowID flow; + AuElement elements[3]; + int i, n, w; + + /* look for an output device */ + for (i = 0; i < AuServerNumDevices(nas_serv); i++) { + if ((AuDeviceKind(AuServerDevice(nas_serv, i)) == + AuComponentKindPhysicalOutput) && + AuDeviceNumTracks(AuServerDevice(nas_serv, i)) == 1) { + device = AuDeviceIdentifier(AuServerDevice(nas_serv, i)); + break; + } + } + + if (device == AuNone) + return 0; + + if (!(flow = AuCreateFlow(nas_serv, NULL))) + return 0; + + + AuMakeElementImportClient(&elements[0], 8012, AuFormatULAW8, 1, AuTrue, size, size / 2, 0, NULL); + AuMakeElementExportDevice(&elements[1], 0, device, 8012, AuUnlimitedSamples, 0, NULL); + AuSetElements(nas_serv, flow, AuTrue, 2, elements, NULL); + + AuStartFlow(nas_serv, flow, NULL); + + AuWriteElement(nas_serv, flow, 0, size, data, AuTrue, NULL); + + AuRegisterEventHandler(nas_serv, AuEventHandlerIDMask, 0, flow, NasEventHandler, NULL); + + while (1) { + AuHandleEvents(nas_serv); + } + + return 1; +} + +static int can_play_nas() +{ + if ((nas_serv = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL))) + return 1; + return 0; +} + +static int play_nas_file(char *file) +{ + struct stat stat_buf; + char *buf; + int ret; + int fd = open(file, O_RDONLY); + if (fd <= 0) + return 0; + + if (!can_play_nas()) + return 0; + + if (stat(file, &stat_buf)) + return 0; + + if (!stat_buf.st_size) + return 0; + + buf = malloc(stat_buf.st_size); + read(fd, buf, stat_buf.st_size); + ret = play_nas(buf, stat_buf.st_size); + free(buf); + return ret; +} + +#endif /* NAS_SOUND */ + +#endif /* !_WIN32 */ + void play_file(char *filename) { #ifndef _WIN32 -#ifdef USE_AO - int ao_driver; -#endif /* USE_AO */ - pid_t pid; + int pid; #endif - if (awaymessage && !(sound_options & OPT_SOUND_WHEN_AWAY)) return; /* check here in case a buddy pounce plays a file while away */ - + if (sound_options & OPT_SOUND_BEEP) { gdk_beep(); return; } -#ifndef _WIN32 - if (!g_file_test(filename, G_FILE_TEST_EXISTS)) { - gchar *tmp = g_strdup_printf(_("Unable to play sound because the chosen filename (%s) does not exist."), filename); - do_error_dialog(tmp, NULL, GAIM_ERROR); - g_free(tmp); - return; + else if (sound_options & OPT_SOUND_NORMAL) { + debug_printf("attempting to play audio file with internal method -- this is unlikely to work\n"); } - - if (sound_options & OPT_SOUND_CMD) { - gchar *command = NULL; - GError *error = NULL; - - if (!sound_cmd[0]) { - do_error_dialog(_("Unable to play sound because the 'Command' sound method has been chosen, but no command has been set."), NULL, GAIM_ERROR); - return; - } - - command = g_strdup_printf(sound_cmd, filename); - - if (g_spawn_command_line_async(command, &error) == FALSE) { - gchar *tmp = g_strdup_printf(_("Unable to play sound because the configured sound command could not be launched: %s"), error->message); - do_error_dialog(tmp, NULL, GAIM_ERROR); - g_free(tmp); - g_error_free(error); - } - - g_free(command); - return; - } - -#ifdef USE_AO - if (!ao_initialized) { - ao_initialize(); - } - - ao_driver = ao_default_driver_id(); - - if (ao_driver == -1) { - do_error_dialog(_("Unable to play sound because no suitable driver could be found."), NULL, GAIM_ERROR); - return; - } - +#ifndef _WIN32 pid = fork(); if (pid < 0) return; else if (pid == 0) { - AFfilehandle file = afOpenFile(filename, "rb", NULL); - if(file) { - ao_device *device; - ao_sample_format format; - - int in_fmt; - int bytes_per_frame; + alarm(30); + + if ((sound_options & OPT_SOUND_CMD) && sound_cmd[0]) { + char *args[4]; + char command[4096]; - format.rate = afGetRate(file, AF_DEFAULT_TRACK); - format.channels = afGetChannels(file, AF_DEFAULT_TRACK); - afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt, - &format.bits); - - bytes_per_frame = format.bits * format.channels / 8; - - device = ao_open_live(ao_driver, &format, NULL); + g_snprintf(command, sizeof(command), sound_cmd, filename); - if (device) { - int frames_read; - char buf[4096]; - int buf_frames = sizeof(buf) / bytes_per_frame; + args[0] = "sh"; + args[1] = "-c"; + args[2] = command; + args[3] = NULL; + execvp(args[0], args); + _exit(0); + } +#ifdef ESD_SOUND + else if (sound_options & OPT_SOUND_ESD) { + if (esd_play_file(NULL, filename, 1)) + _exit(0); + } +#endif - while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK, - buf, buf_frames))) { - if(!ao_play(device, buf, frames_read * bytes_per_frame)) - break; - } - ao_close(device); - } +#ifdef ARTSC_SOUND + else if (sound_options & OPT_SOUND_ARTSC) { + if (artsc_play_file(filename)) + _exit(0); + } +#endif - ao_shutdown(); - afCloseFile(file); +#ifdef NAS_SOUND + else if (sound_options & OPT_SOUND_NAS) { + if (play_nas_file(filename)) + _exit(0); } +#endif + + else if ((sound_options & OPT_SOUND_NORMAL) && + can_play_audio()) { + play_audio_file(filename); + _exit(0); + } + _exit(0); } -#else /* USE_AO */ - gdk_beep(); -#endif /* USE_AO */ - #else /* _WIN32 */ debug_printf("Playing %s\n", filename); if (!PlaySound(filename, 0, SND_ASYNC | SND_FILENAME)) @@ -186,21 +450,13 @@ #endif } -void sound_quit() { -#ifdef USE_AO - if (ao_initialized) { - ao_shutdown(); - } -#endif -} - extern int logins_not_muted; void play_sound(int sound) { if (mute_sounds) return; - + if ((sound == SND_BUDDY_ARRIVE) && !logins_not_muted) return;