/* soundd.d - Accept network clients for live audio source */ /* * Copyright (C) 1995-2005 Jeffrey Chilton * * Permission is granted to anyone to make or distribute copies of * this program, in any medium, provided that the copyright notice * and permission notice are preserved, and that the distributor * grants the recipient permission for further redistribution as * permitted by this notice. * * Author's E-mail address: jwc@chilton.com * */ #include #include #include #include #include #include #include #include #include #include #define AUDIO_PORT 8480 #define AUDIO_DEVICE "/dev/sound" #define TRUE 1 #define BITE_SIZE 16000 #define N_BITE_BUFFERS 20 char Bite[N_BITE_BUFFERS][BITE_SIZE]; unsigned long CurrentBite; unsigned long ClientBite[FD_SETSIZE]; #define N_LOOK_BACK 6 int Listen_fd; int Source_fd; fd_set Client_fds; int Debug = 0; int Max_fd = 0; void doggy(int sigraised) { syslog(LOG_NOTICE, "watchdog signal caught\n"); } main() { register int i, j; struct sockaddr_in server; fd_set r_fds, w_fds; struct timeval to; int data_fd; int buffer; int rc; openlog("soundd", LOG_PID, LOG_USER); signal(SIGPIPE, SIG_IGN); signal(SIGALRM, doggy); /* Start listening for clients */ Listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (Listen_fd < 0) { syslog(LOG_NOTICE, "error opening listen socket\n"); exit(1); } /* Name socket with my made-up server number */ server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(AUDIO_PORT); if (bind(Listen_fd, (struct sockaddr *)&server, sizeof(server))) { syslog(LOG_NOTICE, "error binding listen socket\n"); exit(1); } syslog(LOG_NOTICE, "accepting connections\n"); rc = listen(Listen_fd, 5); if (rc < 0) { syslog(LOG_NOTICE, "error listening\n"); exit(1); } RESTART: /* Open the sound device */ Source_fd = open(AUDIO_DEVICE, O_RDONLY, (mode_t )0); if (Source_fd < 0) { syslog(LOG_NOTICE, "error opening sound device\n"); exit(1); } /* Prime the pump */ rc = read(Source_fd, Bite[0], BITE_SIZE); if (rc < 0) { syslog(LOG_NOTICE, "error reading sound device\n"); exit(1); } /* Main service loop */ CurrentBite = 0; to.tv_sec = 100; to.tv_usec = 0; while (TRUE) { alarm(5); /* Build FD sets for select() call */ FD_ZERO(&r_fds); FD_SET(Listen_fd, &r_fds); FD_SET(Source_fd, &r_fds); FD_ZERO(&w_fds); for (i = 0; i < FD_SETSIZE; i++) { if (FD_ISSET(i, &Client_fds) && ClientBite[i] < CurrentBite) { FD_SET(i, &w_fds); } } /* Wait for whatever... */ rc = select(FD_SETSIZE, &r_fds, &w_fds, 0, &to); if (rc < 0) { syslog(LOG_NOTICE, "select fails\n"); exit(1); } /* Check for sound availiable */ if (FD_ISSET(Source_fd, &r_fds)) { if (CurrentBite % 7200 == 0) { syslog(LOG_NOTICE, "Current bite is #%d\n", CurrentBite); } buffer = CurrentBite++ % N_BITE_BUFFERS; rc = read(Source_fd, Bite[buffer], BITE_SIZE); if (rc < 0) { syslog(LOG_NOTICE, "Error reading sound device (%d): %s\n", rc, strerror(errno)); syslog(LOG_NOTICE, "Current bite %d buffer %d\n", CurrentBite, buffer); syslog(LOG_NOTICE, "Restarting...\n"); close(Source_fd); goto RESTART; } if (rc < BITE_SIZE) { syslog(LOG_NOTICE, "short read from sound device (%d)\n", rc); } } /* Check for writable clients */ for (i = 0; i < FD_SETSIZE; i++) { if (FD_ISSET(i, &w_fds)) { buffer = ClientBite[i] % N_BITE_BUFFERS; rc = write(i, Bite[buffer], BITE_SIZE); if (rc < 0) { close(i); if (Debug) { syslog(LOG_NOTICE, "closed #%d at %d\n", i, CurrentBite); } FD_CLR(i, &Client_fds); } else if (rc < BITE_SIZE) { syslog(LOG_NOTICE, "short write to #%d (%d)\n", i, rc); } ClientBite[i]++; } } /* Check for new clients calling */ if (CurrentBite > N_LOOK_BACK && FD_ISSET(Listen_fd, &r_fds)) { data_fd = accept(Listen_fd, (struct sockaddr *)0, (int *)0); if (data_fd == -1) { syslog(LOG_NOTICE, "accept fails\n"); continue; } FD_SET(data_fd, &Client_fds); ClientBite[data_fd] = CurrentBite - N_LOOK_BACK; if (Debug || data_fd > Max_fd) { syslog(LOG_NOTICE, "new client on #%d at %d\n", data_fd, CurrentBite); Max_fd = data_fd > Max_fd ? data_fd : Max_fd; } } } }