#include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct { short l, r; } stereoent; struct task { int fd, Bits, Stereo, Rate; struct task *next; }; static char Device[256] = "/dev/dsp"; static unsigned ErecPort(void) { unsigned p = 5582; /* magic */ const char *s = Device; while(*s) p += toupper(*s++); /* /DEV/DSP: 6130 */ /* /DEV/DSP1: 6179 */ return p; } /* returns -1 if socket was closed. */ static int senddata(struct task *t, const void *p, unsigned c) { const unsigned char *q = p; unsigned sent=0; while(c) { unsigned try = (sent&1) ? 1 : c; int n; n = send(t->fd, q, try, MSG_NOSIGNAL); if(n < 0 && errno != EAGAIN)return -1; if(n < 0)n = 0; sent += n; if(!(sent & 1)) { struct timeval tv = {0, 100000}; fd_set fds; FD_ZERO(&fds); FD_SET(t->fd, &fds); if(select(t->fd+1, NULL, &fds, NULL, &tv) != 1) { /* Don't keep other streams waiting */ return 0; } } q += n; c -= n; } return 0; } static int sendtask(struct task *t, stereoent *buf, unsigned count, const int Rate) { const double suhde = (double)t->Rate / Rate; const double dresultlen = count * suhde; const unsigned resultlen = dresultlen; stereoent dest[resultlen]; double step = (double)count / resultlen; double pos = 0; unsigned x; for(x=0; xBits == 16) { if(t->Stereo) { return senddata(t, &dest, sizeof dest); } else { short tmp[resultlen]; for(x=0; xBits == 8) { if(t->Stereo) { unsigned char tmp[resultlen*2]; unsigned p=0; for(x=0; x 0)_exit(0); setsid(); memset(&madr, 0, sizeof madr); madr.sin_port = htons(ErecPort()); madr.sin_family = AF_INET; madr.sin_addr.s_addr = 0x0100007F; /* localhost */ Plug = socket(madr.sin_family, SOCK_STREAM, 0); { int dummy; setsockopt(Plug, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof dummy); } bind(Plug, (struct sockaddr *)&madr, sizeof(struct sockaddr)); listen(Plug, 10); fcntl(Plug, F_SETFL, fcntl(Plug, F_GETFL) | O_NONBLOCK); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); /* Inform the child that we're ready by just writing one byte */ write(notificationfd, &Plug, 1); close(notificationfd); for(;;) { struct sockaddr_in radr; stereoent buf[512]; unsigned entnum; int Sock=0; struct task **tmp; fd_set fds; struct timeval tv = {0, 100000}; FD_ZERO(&fds); FD_SET(Plug, &fds); if(Plug>=Sock)Sock = Plug+1; FD_SET(fd, &fds); if(fd >=Sock)Sock = fd+1; select(Sock, &fds, NULL, NULL, &tv); if(FD_ISSET(Plug, &fds)) { int Sock = accept(Plug, (struct sockaddr *)&radr, &radrsize); if(Sock >= 0) { unsigned char c; struct task *tmp = (struct task *)malloc(sizeof(*tmp)); tmp->fd = Sock; read(Sock, &c, 1); tmp->Bits = c; read(Sock, &c, 1); tmp->Stereo = c; read(Sock, &c, 1); tmp->Rate = c; read(Sock, &c, 1); tmp->Rate |= c<<8; fcntl(Sock, F_SETFL, fcntl(Sock, F_GETFL) | O_NONBLOCK); tmp->next = tasks; tasks = tmp; } } if(FD_ISSET(fd, &fds)) { int c=0; entnum = getstereoents(fd, buf, (sizeof(buf) / sizeof(buf[0]))); for(tmp = &tasks; *tmp; ) { if(sendtask(*tmp, buf, entnum, Rate) < 0) { struct task *t = (*tmp)->next; close((*tmp)->fd); free(*tmp); *tmp = t; ++c; } else tmp = &(*tmp)->next; } if(c && !tasks) { /* All clients are gone. I'm dead. * In a typical case, nobody even * realizes that this was process * here... Unless they don't have * TCP/IP, which is exceptional. */ _exit(0); } } } } static int ServeriYhteys(int Bits, int Stereo, int Rate) { struct sockaddr_in madr; char c; int sock; int fd = open(Device, O_RDONLY); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); int err = errno; if(fd >= 0) { int waitpipe[2], p; if(pipe(waitpipe) < 0) { perror("pipe"); return -1; } p = fork(); if(!p) { close(waitpipe[0]); /* Doesn't return */ Serveri(fd, waitpipe[1]); return -1; } close(waitpipe[1]); close(fd); /* Wait until the server says it's ready */ read(waitpipe[0], &p, 1); close(waitpipe[0]); } sock = socket(AF_INET, SOCK_STREAM, 0); if(sock < 0) { perror("socket"); return -1; } memset(&madr, 0, sizeof madr); madr.sin_port = htons(ErecPort()); madr.sin_family = AF_INET; madr.sin_addr.s_addr = 0x0100007F; /* localhost */ if(connect(sock, (struct sockaddr *)&madr, sizeof madr) < 0) { if(err) /* Error code of opening /dev/dsp */ fprintf(stderr, "%s open failed (%s), and erec is not already running.\n", Device, strerror(err)); close(sock); return -1; } c = Bits; send(sock, &c, 1, MSG_NOSIGNAL); c = Stereo; send(sock, &c, 1, MSG_NOSIGNAL); c = Rate&255; send(sock, &c, 1, MSG_NOSIGNAL); c = Rate>>8; send(sock, &c, 1, MSG_NOSIGNAL); return sock; } static int stereo=0; static int Bits =16; static int Rate =44100; static void PrintVersionInfo(void) { printf("erec - shared recording server v"VERSION" (C) 1992,2002 Bisqwit\n"); } #include "cat.h" #include int main(int argc, const char *const *argv) { int fd; int Heelp = 0; argh_init(); argh_add_long("stereo", '2'); argh_add_bool('2'); argh_add_desc('2', "Specifies stereo sound. Default is mono.", NULL); argh_add_long("mono", 'm'); argh_add_bool('m'); argh_add_desc('m', "Redundant. It's here for esd compatibility.", NULL); argh_add_long("byte", 'b'); argh_add_bool('b'); argh_add_desc('b', "8-bit mode. Normally 16-bit mode.", NULL); argh_add_long("word", '6'); argh_add_bool('6'); argh_add_desc('6', "16-bit mode. Redundant.", NULL); argh_add_long("rate", 'r'); argh_add_int('r',18,999999); argh_add_desc('r', "Specifies recording rate. 44100 is default.", ""); argh_add_long("device", 'd'); argh_add_string('d',1,1023); argh_add_desc('d', "Specify device.", ""); argh_add_long("help", 'h'); argh_add_bool('h'); argh_add_desc('h', "Help", NULL); argh_add_long("version",'V'); argh_add_bool('V'); argh_add_desc('V', "Version information", NULL); argh_start_parse(argc, argv); for(;;) { int c = argh_get_param(); if(c == -1)break; switch(c) { case 'V': PrintVersionInfo(); return 0; case 'h': Heelp = 1; break; case '2': if(argh_get_bool())++stereo;else stereo=0; break; case 'b': Bits = argh_get_bool() ? 8 : 16; break; case '6': Bits = argh_get_bool() ? 16 : 8; break; case 'm': if(argh_get_bool())stereo = 0;else ++stereo; break; case 'r': Rate = argh_get_int(); break; case 'd': strncpy(Device, argh_get_string(), sizeof Device); Device[sizeof(Device)-1] = 0; break; default: { /* */ } } } if(!argh_ok())return -1; if(Heelp) { PrintVersionInfo(); printf( "\nAllows multiple applications request recorded data" "\nat the same time with different stream attributes.\n"); printf( "Usage: erec [ [...]]\n" "Options:\n"); argh_list_options(); return 0; } fd = ServeriYhteys(Bits, stereo, Rate); if(fd < 0) { perror(*argv); return errno; } argh_done(); dup2(fd, 0); cat(); /* doesn't return */ return -1; }