9 #include <sys/socket.h>
10 #include <arpa/inet.h>
11 #include <sys/types.h>
17 #define SOURCE_VERSION "0.0"
18 #define BOUNDARY "arflebarfle"
20 typedef enum { SNAPSHOT, STREAM } answer_t;
28 /* signal fresh frames */
29 pthread_mutex_t db = PTHREAD_MUTEX_INITIALIZER;
30 pthread_cond_t db_update = PTHREAD_COND_INITIALIZER;
32 /* global JPG frame, this is more or less the "database" */
35 /* thread for clients that connected to this server */
36 void *client_thread( void *arg ) {
37 int fd = *((int *)arg);
41 char buffer[1024] = {0};
44 if (arg!=NULL) free(arg); else exit(1);
46 /* set timeout to 5 seconds */
51 if( select(fd+1, &fds, NULL, NULL, &to) <= 0) {
56 /* find out if we should deliver something other than a stream */
58 sprintf(buffer, "HTTP/1.0 200 OK\r\n" \
59 "Server: OSS Streamer\r\n" \
60 "Content-Type: audio/wav\r\n" \
61 "Cache-Control: no-cache\r\n" \
62 "Cache-Control: private\r\n" \
63 "Pragma: no-cache\r\n" \
67 ok = ( write(fd, buffer, strlen(buffer)) >= 0)?1:0;
69 while ( ok >= 0 && !stop ) {
71 /* having a problem with windows (do we not always) browsers not updating the
72 stream display, unless the browser cache is disabled - try and implement a delay
73 to allow movement to end before streem goes on - kind of works, but not well enough */
75 /* wait for fresh frames */
76 pthread_cond_wait(&db_update, &db);
79 memcpy(frame, g_buf, BUF_SIZE);
81 pthread_mutex_unlock( &db );
83 ok = ( write(fd, frame, BUF_SIZE) >= 0)?1:0;
93 /* the single writer thread */
94 void *get_thread( void *arg ) {
96 char rbuffer[BUF_SIZE];
100 if( read(source_dev,rbuffer,BUF_SIZE) < 0 ) {
101 fprintf(stderr, "Error grabbing\n");
105 /* copy frame to global buffer */
106 pthread_mutex_lock( &db );
108 memcpy(g_buf, rbuffer, BUF_SIZE);
110 /* signal fresh_frame */
111 pthread_cond_broadcast(&db_update);
112 pthread_mutex_unlock( &db );
114 /* only use usleep if the fps is below 5, otherwise the overhead is too long */
120 void help(char *progname)
122 fprintf(stderr, "------------------------------------------------------------------\n");
123 fprintf(stderr, "Usage: oss-stream" \
124 " [-h | --help ]........: display this help\n" \
125 " [-d | --device ]......: video device to open (your camera)\n" \
126 " [-p | --port ]........: TCP-port for the server\n" \
127 " [-v | --version ].....: display version information\n" \
128 " [-b | --background]...: fork to the background, daemon mode\n");
129 fprintf(stderr, "------------------------------------------------------------------\n");
132 void signal_handler(int sigm) {
133 /* signal "stop" to threads */
136 /* cleanup most important structures */
137 fprintf(stderr, "shutdown...\n");
140 perror ("close sd");;
141 pthread_cond_destroy(&db_update);
142 pthread_mutex_destroy(&db);
147 void daemon_mode(void) {
152 fprintf(stderr, "fork() failed\n");
160 fprintf(stderr, "setsid() failed\n");
166 fprintf(stderr, "fork() failed\n");
170 fprintf(stderr, "forked to background (%d)\n", fr);
181 open("/dev/null", O_RDWR);
186 /* #########################################################################
188 ######################################################################### */
189 int main(int argc, char *argv[])
191 struct sockaddr_in addr;
193 pthread_t client, get;
194 char *dev = "/dev/dsp";
195 unsigned int stream_port = 0;
199 int option_index = 0, c=0;
200 static struct option long_options[] = \
202 {"h", no_argument, 0, 0},
203 {"help", no_argument, 0, 0},
204 {"d", required_argument, 0, 0},
205 {"device", required_argument, 0, 0},
206 {"p", required_argument, 0, 0},
207 {"port", required_argument, 0, 0},
208 {"v", no_argument, 0, 0},
209 {"version", no_argument, 0, 0},
210 {"b", no_argument, 0, 0},
211 {"background", no_argument, 0, 0},
215 c = getopt_long_only(argc, argv, "", long_options, &option_index);
217 /* no more options to parse */
220 /* unrecognized option */
221 if(c=='?'){ help(argv[0]); return 0; }
223 switch (option_index) {
234 dev = strdup(optarg);
240 stream_port=htons(atoi(optarg));
246 printf("OSS Streamer Version: %s\n" \
247 "Compilation Date....: %s\n" \
248 "Compilation Time....: %s\n", SOURCE_VERSION, __DATE__, __TIME__);
264 if ( stream_port==0 ) {
265 fprintf(stderr, "server port not set\n");
269 /* ignore SIGPIPE (send if transmitting to closed sockets) */
270 signal(SIGPIPE, SIG_IGN);
271 if (signal(SIGINT, signal_handler) == SIG_ERR) {
272 fprintf(stderr, "could not register signal handler\n");
276 /* fork to the background */
281 /* allocate audio datastructure */
283 /* open video device and prepare data structure */
284 source_dev = open(dev,O_RDONLY);
285 if (source_dev < 0) {
286 fprintf(stderr, "error opening source device\n");
290 /* open socket for server */
291 sd = socket(PF_INET, SOCK_STREAM, 0);
293 fprintf(stderr, "socket failed\n");
297 /* ignore "socket already in use" errors */
298 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
299 perror("setsockopt(SO_REUSEADDR) failed");
303 /* configure server address to listen to all local IPs */
304 memset(&addr, 0, sizeof(addr));
305 addr.sin_family = AF_INET;
306 addr.sin_port = stream_port;
307 addr.sin_addr.s_addr = htonl(INADDR_ANY);
308 if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) {
309 fprintf(stderr, "bind failed\n");
314 /* start listening on socket */
315 if ( listen(sd, 10) != 0 ) {
316 fprintf(stderr, "listen failed\n");
320 /* start to read the camera, push picture buffers into global buffer */
321 pthread_create(&get, 0, get_thread, NULL);
324 /* start motor control server */
326 /* create a child for every client that connects */
328 int *pfd = (int *)calloc(1, sizeof(int));
329 *pfd = accept(sd, 0, 0);
330 pthread_create(&client, NULL, &client_thread, pfd);
331 pthread_detach(client);