9 #include <sys/socket.h>
10 #include <arpa/inet.h>
11 #include <sys/types.h>
17 #define SOURCE_VERSION "0.0"
19 typedef enum { SNAPSHOT, STREAM } answer_t;
27 /* signal fresh frames */
28 pthread_mutex_t db = PTHREAD_MUTEX_INITIALIZER;
29 pthread_cond_t db_update = PTHREAD_COND_INITIALIZER;
31 /* global JPG frame, this is more or less the "database" */
34 /* thread for clients that connected to this server */
35 void *client_thread( void *arg ) {
36 int fd = *((int *)arg);
40 char buffer[1024] = {0};
43 if (arg!=NULL) free(arg); else exit(1);
45 /* set timeout to 5 seconds */
50 if( select(fd+1, &fds, NULL, NULL, &to) <= 0) {
55 /* find out if we should deliver something other than a stream */
57 sprintf(buffer, "HTTP/1.0 200 OK\r\n" \
58 "Server: OSS Streamer\r\n" \
59 "Content-Type: audio/wav\r\n" \
60 "Cache-Control: no-cache\r\n" \
61 "Cache-Control: private\r\n" \
62 "Pragma: no-cache\r\n" \
66 ok = ( write(fd, buffer, strlen(buffer)) >= 0)?1:0;
68 while ( ok >= 0 && !stop ) {
70 /* having a problem with windows (do we not always) browsers not updating the
71 stream display, unless the browser cache is disabled - try and implement a delay
72 to allow movement to end before streem goes on - kind of works, but not well enough */
74 /* wait for fresh frames */
75 pthread_cond_wait(&db_update, &db);
78 memcpy(frame, g_buf, BUF_SIZE);
80 pthread_mutex_unlock( &db );
82 ok = ( write(fd, frame, BUF_SIZE) >= 0)?1:0;
92 /* the single writer thread */
93 void *get_thread( void *arg ) {
95 char rbuffer[BUF_SIZE];
99 if( fread(rbuffer,1,BUF_SIZE,source_dev) < 0 ) {
100 fprintf(stderr, "Error grabbing\n");
104 /* copy frame to global buffer */
105 pthread_mutex_lock( &db );
107 memcpy(g_buf, rbuffer, BUF_SIZE);
109 /* signal fresh_frame */
110 pthread_cond_broadcast(&db_update);
111 pthread_mutex_unlock( &db );
113 /* only use usleep if the fps is below 5, otherwise the overhead is too long */
119 void help(char *progname)
121 fprintf(stderr, "------------------------------------------------------------------\n");
122 fprintf(stderr, "Usage: oss-stream" \
123 " [-h | --help ]........: display this help\n" \
124 " [-d | --device ]......: audio device to open (your camera)\n" \
125 " [-p | --port ]........: TCP-port for the server\n" \
126 " [-v | --version ].....: display version information\n" \
127 " [-b | --background]...: fork to the background, daemon mode\n");
128 fprintf(stderr, "------------------------------------------------------------------\n");
131 void signal_handler(int sigm) {
132 /* signal "stop" to threads */
135 /* cleanup most important structures */
136 fprintf(stderr, "shutdown...\n");
139 perror ("close sd");;
140 pthread_cond_destroy(&db_update);
141 pthread_mutex_destroy(&db);
146 void daemon_mode(void) {
151 fprintf(stderr, "fork() failed\n");
159 fprintf(stderr, "setsid() failed\n");
165 fprintf(stderr, "fork() failed\n");
169 fprintf(stderr, "forked to background (%d)\n", fr);
180 open("/dev/null", O_RDWR);
185 /* #########################################################################
187 ######################################################################### */
188 int main(int argc, char *argv[])
190 struct sockaddr_in addr;
192 pthread_t client, get;
193 char *dev = "/dev/dsp";
194 unsigned int stream_port = 0;
198 int option_index = 0, c=0;
199 static struct option long_options[] = \
201 {"h", no_argument, 0, 0},
202 {"help", no_argument, 0, 0},
203 {"d", required_argument, 0, 0},
204 {"device", required_argument, 0, 0},
205 {"p", required_argument, 0, 0},
206 {"port", required_argument, 0, 0},
207 {"v", no_argument, 0, 0},
208 {"version", no_argument, 0, 0},
209 {"b", no_argument, 0, 0},
210 {"background", no_argument, 0, 0},
214 c = getopt_long_only(argc, argv, "", long_options, &option_index);
216 /* no more options to parse */
219 /* unrecognized option */
220 if(c=='?'){ help(argv[0]); return 0; }
222 switch (option_index) {
233 dev = strdup(optarg);
239 stream_port=htons(atoi(optarg));
245 printf("OSS Streamer Version: %s\n" \
246 "Compilation Date....: %s\n" \
247 "Compilation Time....: %s\n", SOURCE_VERSION, __DATE__, __TIME__);
263 if ( stream_port==0 ) {
264 fprintf(stderr, "server port not set\n");
268 /* ignore SIGPIPE (send if transmitting to closed sockets) */
269 signal(SIGPIPE, SIG_IGN);
270 if (signal(SIGINT, signal_handler) == SIG_ERR) {
271 fprintf(stderr, "could not register signal handler\n");
275 /* fork to the background */
280 /* allocate audio datastructure */
282 /* open audio device and prepare data structure */
283 if (strcmp(dev,"stdin")==0) {
286 source_dev = fopen(dev,"r");
288 if (source_dev == NULL) {
289 fprintf(stderr, "error opening source device\n");
293 /* open socket for server */
294 sd = socket(PF_INET, SOCK_STREAM, 0);
296 fprintf(stderr, "socket failed\n");
300 /* ignore "socket already in use" errors */
301 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
302 perror("setsockopt(SO_REUSEADDR) failed");
306 /* configure server address to listen to all local IPs */
307 memset(&addr, 0, sizeof(addr));
308 addr.sin_family = AF_INET;
309 addr.sin_port = stream_port;
310 addr.sin_addr.s_addr = htonl(INADDR_ANY);
311 if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) {
312 fprintf(stderr, "bind failed\n");
317 /* start listening on socket */
318 if ( listen(sd, 10) != 0 ) {
319 fprintf(stderr, "listen failed\n");
323 /* start to read the camera, push picture buffers into global buffer */
324 pthread_create(&get, 0, get_thread, NULL);
327 /* start motor control server */
329 /* create a child for every client that connects */
331 int *pfd = (int *)calloc(1, sizeof(int));
332 *pfd = accept(sd, 0, 0);
333 pthread_create(&client, NULL, &client_thread, pfd);
334 pthread_detach(client);