root/vic/trunk/main.cc @ 733

Revision 733, 14.5 KB (checked in by ucackha, 16 years ago)

Updated for windows and tcl/tk8

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*-
2 * Copyright (c) 1993-1994 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by the University of
16 *      California, Berkeley and the Network Research Group at
17 *      Lawrence Berkeley Laboratory.
18 * 4. Neither the name of the University nor of the Laboratory may be used
19 *    to endorse or promote products derived from this software without
20 *    specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34static const char rcsid[] =
35    "@(#) $Header$ (LBL)";
36
37#include <stdio.h>
38#include <stdlib.h>
39#ifdef WIN32
40#include <windows.h>
41#else
42#include <unistd.h>
43#endif
44#include <errno.h>
45#include <signal.h>
46#include <string.h>
47#include <ctype.h>
48#ifdef WIN32
49#include <winsock.h>
50#include <process.h>
51#include <time.h>
52#else
53#include <sys/param.h>
54#include <netinet/in.h>
55#include <netdb.h>
56#include <sys/file.h>
57#include <sys/utsname.h>
58#endif
59#ifdef sgi
60#include <getopt.h>
61#include <math.h>
62#endif
63#include <X11/Xlib.h>
64#include <X11/Xutil.h>
65
66extern "C" {
67#include <tk.h>
68#ifdef USE_SHM
69#ifdef sgi
70#define XShmAttach __XShmAttach__
71#endif
72#include <X11/extensions/XShm.h>
73#ifdef _AIX
74extern Bool XShmQueryExtension (Display *dpy);
75#endif
76#ifdef sgi
77#undef XShmAttach
78int XShmAttach(Display*, XShmSegmentInfo*);
79#endif
80#include <sys/ipc.h>
81#include <sys/shm.h>
82#if defined(sun) && !defined(__svr4__)
83int shmget(key_t, int, int);
84int shmctl(int shmid, int cmd, struct shmid_ds *);
85#endif
86#endif
87}
88
89#if defined(sun) && !defined(__svr4__)
90extern "C" int gettimeofday(struct timeval*, struct timezone*);
91extern "C" int nice(int incr);
92#endif
93#if defined(sun) || defined(__osf__)
94extern "C" int gethostname(char* name, int len);
95#endif
96
97#include "inet.h"
98#include "Tcl.h"
99#include "transmitter.h"
100
101/*XXX*/
102#define PROTOTYPES 1
103#include "global.h"
104#include "md5.h"
105
106#if defined(sun) && defined(__svr4__)
107#include <sys/utsname.h>
108#define gethostname(name, len) { \
109        struct utsname _uts_; \
110\
111        if (uname(&_uts_) < 0) { \
112                perror("uname"); \
113                exit(1); \
114        }\
115\
116        strcpy((name), _uts_.nodename); \
117}
118#endif
119 
120static void
121usage()
122{
123        fprintf(stderr, "\
124Usage: vic [-HPs] [-A nv|ivs|rtp] [-B maxbps] [-C conf]\n\
125\t[-c ed|gray|od|quantize] [-D device] [-d display]\n\
126\t[-f bvc|cellb|h261|jpeg|nv] [-F maxfps] [-I channel]\n\
127\t[-K key ] [-M colormap] [-m mtu] [-N session]\n\
128\t[-n atm|ip|rtip] [-o clipfile] [-t ttl] [-U interval]\n\
129\t[-u script] [-V visual] [-X resource=value] dest/port[/fmt/ttl]\n"
130        );
131        exit(1);
132}
133
134static class UsageCommand : public TclObject {
135public:
136        UsageCommand() : TclObject("usage") {}
137        int command(int argc, const char*const* argv) {
138                usage();
139                /*NOTREACHED*/
140                return (0);
141        }
142} cmd_usage;
143
144#ifndef SIGARGS
145#ifdef __SUNPRO_CC
146#define SIGARGS int arg
147#else
148#define SIGARGS ...
149#endif
150#endif
151
152extern void adios();
153
154static SIGRET
155ciao(SIGARGS)
156{
157        adios();
158}
159
160static class AdiosCommand : public TclObject {
161public:
162        AdiosCommand() : TclObject("adios") {}
163        int command(int argc, const char*const* argv) {
164                adios();
165                /*NOTREACHED*/
166                return (0);
167        }
168} cmd_adios;
169
170static class HaveFontCommand : public TclObject {
171public:
172        HaveFontCommand() : TclObject("havefont") {}
173        int command(int argc, const char*const* argv) {
174                Tcl& t = Tcl::instance();
175                if (argc != 2)
176                        t.result("0");
177                else {
178                        Tk_Window tk = t.tkmain();
179                        Tk_Uid uid = Tk_GetUid((char*)argv[1]);
180                        Tk_Font p = Tk_GetFont(t.interp(), tk, uid);
181                        t.result(p != 0 ? "1" : "0");
182                }
183                return (TCL_OK);
184        }
185} cmd_havefont;
186
187static class GetHostNameCommand : public TclObject {
188public:
189        GetHostNameCommand() : TclObject("gethostname") {}
190        int command(int argc, const char*const* argv) {
191                Tcl& tcl = Tcl::instance();
192                char* bp = tcl.buffer();
193                tcl.result(bp);
194                gethostname(bp, MAXHOSTNAMELEN);
195                return (TCL_OK);
196        }
197} cmd_gethostname;
198
199extern "C" char version[];
200
201static class VersionCommand : public TclObject {
202public:
203        VersionCommand() : TclObject("version") {}
204        int command(int argc, const char*const* argv) {
205                Tcl::instance().result(version);
206                return (TCL_OK);
207        }
208} cmd_version;
209
210#ifndef USE_SHM
211int use_shm = 0;
212#else
213int use_shm = 1;
214
215#if defined(sgi) && !defined(IRIX6_2)
216Bool XShmQueryExtension(Display* dpy)
217{
218        int mj, mn;
219        Bool sp;
220        return XShmQueryVersion(dpy, &mj, &mn, &sp);
221}
222#endif
223
224static int
225noXShm(ClientData, XErrorEvent*)
226{
227        /*
228         * can get called twice, because on some systems the
229         * XShmDetach after a failed XShmAttach is an error
230         * (i.e., a second error), while on others (bsdi), the
231         * detach is necessary so we cannot omit it
232         */
233        if (use_shm)
234                fprintf(stderr, "vic: warning: not using shared memory\n");
235        use_shm = 0;
236        return (0);
237}
238
239/*
240 * XXX this is a hack to see if we can used shared memory.
241 * if the X server says we can, and we're on the same
242 * host as the X server, then we are golden.
243 */
244static void
245checkXShm(Tk_Window tk, const char*)
246{
247        Display* dpy = Tk_Display(tk);
248
249        if (XShmQueryExtension(dpy) == 0) {
250                fprintf(stderr,
251                        "vic: warning: server doesn't support shared memory\n");
252                use_shm = 0;
253                return;
254        }
255        XShmSegmentInfo si;
256        if ((si.shmid = shmget(IPC_PRIVATE, 512, IPC_CREAT|0777)) < 0) {
257                if (use_shm)
258                        fprintf(stderr,
259                                "vic: warning: no shared memory available\n");
260                use_shm = 0;
261                return;
262        }
263        si.readOnly = 1;
264        XSync(dpy, 0);
265        Tk_ErrorHandler handler = Tk_CreateErrorHandler(dpy, -1, -1, -1,
266                                                        noXShm, 0);
267        XShmAttach(dpy, &si);
268        XSync(dpy, 0);
269        XShmDetach(dpy, &si);
270        Tk_DeleteErrorHandler(handler);
271        (void)shmctl(si.shmid, IPC_RMID, 0);
272}
273#endif
274
275extern "C" char *optarg;
276extern "C" int optind;
277extern "C" int opterr;
278
279const char*
280disparg(int argc, const char** argv, const char* optstr)
281{
282        const char* display = 0;
283        int op;
284        while ((op = getopt(argc, (char**)argv, (char*)optstr)) != -1) {
285                if (op == 'd') {
286                        display = optarg;
287                        break;
288                }
289                else if (op == '?')
290                        usage();
291        }
292#ifdef linux
293        optind = 0;
294#else
295        optind = 1;
296#endif
297        return (display);
298}
299
300char*
301parse_assignment(char* cp)
302{
303        cp = strchr(cp, '=');
304        if (cp != 0) {
305                *cp = 0;
306                return (cp + 1);
307        } else
308                return ("true");
309}
310
311#ifdef __hpux
312#include <sys/socket.h>
313gethostid()
314{
315        int id;
316        char hostname[256];             /* 255 is max legal DNS name */
317        size_t hostname_size = 256;
318        struct hostent *hostp;
319        struct in_addr addru;           /* union for conversion */
320
321        (void) gethostname(hostname, hostname_size);
322        hostname[hostname_size] = '\0'; /* make sure it is null-terminated */
323
324        hostp = gethostbyname(hostname);
325        if(hostp == NULL)
326                /* our own name was not found!  punt. */
327                id = 0;
328        else {
329                /* return first address of host */
330                memcpy(&(addru.s_addr), hostp->h_addr_list[0], 4);
331                id = addru.s_addr;
332        }
333 
334        return id;
335}
336#endif
337
338#ifdef __svr4__
339#include <sys/systeminfo.h>
340#define gethostid xgethostid
341gethostid()
342{
343        char wrk[32];
344        if (sysinfo(SI_HW_SERIAL, wrk, sizeof(wrk)) > 0)
345                return (atoi(wrk));
346        return (0);
347}
348#endif
349
350/*
351 * From the RTP spec.
352 */
353u_int32_t
354heuristic_random()
355{
356        struct {
357                struct  timeval tv;
358                clock_t cpu;
359                pid_t   pid;
360                u_long  hid;
361                uid_t   uid;
362                gid_t   gid;
363                struct  utsname name;
364        } s;
365
366        gettimeofday(&s.tv, 0);
367        uname(&s.name);
368        s.cpu  = clock();
369        s.pid  = getpid();
370        s.hid  = gethostid();
371        s.uid  = getuid();
372        s.gid  = getgid();
373
374        MD5_CTX context;
375        MD5Init(&context);
376        MD5Update(&context, (u_char*)&s, sizeof(s));
377        u_int32_t out[4];
378        MD5Final((u_char *)out, &context);
379        return (out[0] ^ out[1] ^ out[2] ^ out[3]);
380}
381
382void loadbitmaps(Tcl_Interp* tcl)
383{
384        static char rev[] = {
385                0x30, 0x78, 0x7c, 0x7e, 0x7f, 0x7f, 0x7e, 0x7c, 0x78, 0x30
386        };
387        Tk_DefineBitmap(tcl, Tk_GetUid("rev"), rev, 7, 10);
388        static char fwd[] = {
389                0x06, 0x0f, 0x1f, 0x3f, 0x7f, 0x7f, 0x3f, 0x1f, 0x0f, 0x06
390        };
391        Tk_DefineBitmap(tcl, Tk_GetUid("fwd"), fwd, 7, 10);
392}
393
394extern "C" int Tk_StripchartCmd(ClientData, Tcl_Interp*, int ac, char** av);
395#ifdef WIN32
396extern "C" int WinPutsCmd(ClientData, Tcl_Interp*, int ac, char** av);
397extern "C" int WinGetUserName(ClientData, Tcl_Interp*, int ac, char** av);
398extern "C" int WinPutRegistry(ClientData, Tcl_Interp*, int ac, char** av);
399extern "C" int WinGetRegistry(ClientData, Tcl_Interp*, int ac, char** av);
400#endif
401
402extern "C" {
403int
404TkPlatformInit(Tcl_Interp *interp)
405{
406        Tcl_SetVar(interp, "tk_library", ".", TCL_GLOBAL_ONLY);
407#ifndef WIN32
408        extern void TkCreateXEventSource(void);
409        TkCreateXEventSource();
410#endif
411        return (TCL_OK);
412}
413
414void *TkSetPlatformInit(int (*func)(Tcl_Interp *));
415
416}
417
418int
419main(int argc, const char** argv)
420{
421        srandom(heuristic_random());
422
423#ifdef SIGHUP
424        signal(SIGHUP, ciao);
425#endif
426        signal(SIGINT, ciao);
427        signal(SIGTERM, ciao);
428
429#ifdef WIN32_NOT
430        TkSetPlatformInit(TkPlatformInit);
431#endif
432
433        opterr = 0;
434        const char* options =
435                "A:B:C:c:D:d:f:F:HI:K:M:m:N:n:o:Pq:sT:t:U:u:V:X:";
436        const char* display = disparg(argc, (const char**)argv, options);
437
438        Tcl::init("vic");
439        Tcl& tcl = Tcl::instance();
440#ifdef WIN32
441        if (display == NULL)
442                display = "localhost:0";
443#endif
444        tcl.evalf(display?
445                    "set argv \"-name vic -display %s\"" :
446                    "set argv \"-name vic\"",
447                  display);
448        Tk_Window tk = 0;
449        if (Tk_Init(tcl.interp()) == TCL_OK)
450                tk = Tk_MainWindow(tcl.interp());
451        if (tk == 0) {
452                fprintf(stderr, "vic: %s\n", tcl.result());
453                exit(1);
454        }
455        tcl.tkmain(tk);
456
457        loadbitmaps(tcl.interp());
458        tcl.CreateCommand("stripchart", Tk_StripchartCmd, (ClientData)tk);
459#ifdef WIN32
460        tcl.CreateCommand("puts", WinPutsCmd, (ClientData)tk);
461        tcl.CreateCommand("getusername", WinGetUserName, (ClientData)tk);
462        tcl.CreateCommand("putregistry", WinPutRegistry, (ClientData)tk);
463        tcl.CreateCommand("getregistry", WinGetRegistry, (ClientData)tk);
464#endif
465        EmbeddedTcl::init();
466        tcl.evalc("init_resources");
467
468        int op;
469        while ((op = getopt(argc, (char**)argv, (char*)options)) != -1) {
470                switch (op) {
471
472                default:
473                        usage();
474
475                case 'A':
476                        tcl.add_option("sessionType", optarg);
477                        if (strcasecmp(optarg, "nv") == 0)
478                                tcl.add_default("defaultFormat", "nv");
479                        else if (strcasecmp(optarg, "ivs") == 0)
480                                tcl.add_default("defaultFormat", "h.261");
481                        break;
482
483                case 'B':
484                        tcl.add_option("maxbw", optarg);
485                        break;
486
487                case 'C':
488                        tcl.add_option("conferenceName", optarg);
489                        break;
490
491                case 'c':
492                        tcl.add_option("dither", optarg);
493                        break;
494
495                case 'D':
496                        tcl.add_option("device", optarg);
497                        break;
498
499                case 'd':
500                        break;
501
502                case 'f':
503                        tcl.add_option("defaultFormat", optarg);
504                        break;
505
506                case 'F':
507                        tcl.add_option("maxfps", optarg);
508                        break;
509
510                case 'H':
511                        tcl.add_option("useHardwareDecode", "true");
512                        break;
513
514                case 'I':
515                        tcl.add_option("confBusChannel", optarg);
516                        break;
517
518                case 'K':
519                        /*XXX probably do not want this in X server*/
520                        tcl.add_option("sessionKey", optarg);
521                        break;
522
523                case 'M':
524                        tcl.add_option("colorFile", optarg);
525                        break;
526
527                case 'm':
528                        tcl.add_option("mtu", optarg);
529                        break;
530
531                case 'N':
532                        tcl.add_option("rtpName", optarg);
533                        break;
534
535                case 'n':
536                        tcl.add_option("network", optarg);
537                        break;
538
539                case 'o':
540                        tcl.add_option("outfile", optarg);
541                        break;
542
543                case 'P':
544                        tcl.add_option("privateColormap", "true");
545                        break;
546
547                case 'q':
548                        tcl.add_option("jpegQfactor", optarg);
549                        break;
550
551                case 's':
552                        use_shm = 0;
553                        break;
554
555                case 't':
556                        tcl.add_option("defaultTTL", optarg);
557                        break;
558
559                case 'T':
560                        tcl.add_option("softJPEGthresh", optarg);
561                        break;
562
563                case 'u':
564                        tcl.add_option("startupScript", optarg);
565                        break;
566
567                case 'U':
568                        tcl.add_option("stampInterval", optarg);
569                        break;
570
571                case 'V':
572                        tcl.add_option("visual", optarg);
573                        break;
574
575                case 'X':
576                        {
577                                const char* value = parse_assignment(optarg);
578                                tcl.add_option(optarg, value);
579                        }
580                        break;
581                }
582        }
583#ifdef USE_SHM
584        if (use_shm)
585                checkXShm(tk, display);
586#endif
587
588        const char* dst;
589        if (optind < argc && argc > 1) {
590                dst = argv[optind];
591                if (argc - optind > 1) {
592                        fprintf(stderr,
593                                "vic: extra arguments (starting with `%s')\n",
594                                argv[optind + 1]);
595                        exit(1);
596                }
597        } else if ((dst = tcl.attr("defaultHostSpec")) == 0) {
598                fprintf(stderr, "vic: destination address required\n");
599                exit(1);
600        }
601        tcl.add_option("defaultHostSpec", dst);
602#ifdef notdef
603        const char* outfile = tcl.attr("outfile");
604        if (outfile != 0) {
605                int fd = open(outfile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
606                if (fd < 0) {
607                        fprintf(stderr, "vic: ");
608                        perror(outfile);
609                        exit(1);
610                }
611                Framer::dump(fd);
612        }
613#endif
614        tcl.evalc("vic_main");
615
616        /*
617         * re-nice the vic process before we start processing video
618         * so that video processing won't screw up the local audio.
619         */
620        int pri = atoi(tcl.attr("priority"));
621        if (pri > 0)
622                nice(pri);
623
624        /*
625         * Randomize start sequence number and media timestamp
626         * per in case we turn on encryption.(XXX should re-do
627         * this when changing keys).
628         */
629        /*XXX*/
630        Transmitter::seqno(random());
631
632#ifdef DEBUG_X_SYNCRONOUSLY
633        XSynchronize(Tk_Display(tk), True);
634#endif
635
636        /* win32 needs the following to get the initial window painted */
637        tcl.evalc("update idletasks");
638#ifdef noyet
639        while (tk_NumMainWindows > 0) {
640                /*
641                 * Tk doesn't give priority to the X server so file handlers
642                 * (i.e., packets from the network) can starve the window
643                 * system (technically, tk lets one X event through per file
644                 * event, but a file event can trigger more than one X event
645                 * so the X server loses to a high-rate video source).
646                 * The solution is to let the X server go first by only
647                 * processing file handlers when their are no pending
648                 * X events.
649                 */
650                if (Tk_DoOneEvent(TK_X_EVENTS|TK_IDLE_EVENTS|
651                                  TK_DONT_WAIT) == 0)
652                                Tk_DoOneEvent(0);
653        }
654#else
655        Tk_MainLoop();
656#endif
657        adios();
658        return (0);
659}
Note: See TracBrowser for help on using the browser.