Home

About
General Info
FAQ
Mailing Lists

Users
Getting Started
Downloads
Tools

Developers
Getting Started
Source Code
Documentation
- Object APIs

Status
Compatibility
Bugs
Feature Requests

Resources
Publications
Workshops
Links

QuickSearch



Scripting Mash Applets
The Mash programming model is based on an architecture where multimedia data is generated by one or more source objects, piped through one or more filter objects, and eventually, consumed by one or more sink objects. A source, for example, might be a video capture device, a filter might be a color space converter, a compressor, a packetizer, or the like, while a sink might be a network transmission protocol. We call this scheme the ''VuSystem Architecture'' because it was first cleanly articulated by the authors of that system.

The VuSystem toolkit was built on top of an object-oriented Tcl extension that later evolved into Object Tcl (OTcl). C++ classes implement multimedia objects that produce, consume, or filter real-time media streams and a Tcl shadow object mirrors each C++ object. Methods invoked on the Tcl shadow object are dispatched to the C++ object. Objects are created, composed, and configured from Tcl and the interconnections between objects can be rearranged while running. In addition to its elegant, object-oriented architecture, the VuSystem is built around a consistent and uniform fine-grained object model with inheritance.

Our approach elaborates the VuSystem Architecture by bridging the gap between C++ and OTcl. We view an object as an abstract entity whose methods can be implemented on either side of the OTcl/C++ boundary. C++ code can invoke methods defined in OTcl, while OTcl code can invoke methods defined in C++. The common idiom whereby Tcl callbacks are installed in C data structures is replaced by a simple, clean object method API. A callback from C++ into Tcl is simply a self-referential method invocation (where the target method happens to be implemented in Tcl).

In our OTcl/C++ framework, called "TclCL'', (for Tcl with CLasses), fine-grained objects are implemented in C++ and complex abstractions are built by coalescing these fine-grained objects into ``macro-objects'' using scripts to glue together components. To support a clean and manageable programming model, the details of a macro-object can be encapsulated in an OTcl object with a uniform method API. In turn, macro-objects can be arranged into larger and richer macro-objects thereby giving the toolkit programmer multiple levels of abstraction and allowing her to choose the appropriate level of detail for a given implementation.

More details on the overall mash system architecture and the design rationale for the underlying split-object programming model can be found in our NOSSDAV '97 paper, also available from our publications page.


The Scripting API
The Mash scripting API is defined by the ensemble of APIs to a large collection of split OTcl/C++ objects as well as a number of pure OTcl objects (that internally contain split OTcl/C++ objects). This section of our documentation describes the scripting API to these objects. We classify the objects into two categories:

  • Agents that are often active, implement a rich set of functions, and provide high-level building blocks for programming multimedia apps; and
  • Core Objects that tend to be passive and implement fairly low-level functionality.

The links above point to a detailed index of the APIs that define the objects. In the rest of this page, we describe the overall structure of the mash interpreter and scripting model.


Tcl Resources
If you are new to Tcl and would like to learn it to help you program mash scripts, the best resource is probably John Ousterhout's original book, Tcl and the Tk Toolkit. Several other good books have been published as well. The Tcl/Tk project is led by SunScript.

One problem with Tcl is that it was not originally designed to serve as the primary language in very large software systems. Because of this, the language does not have features that support large projects and modularization. Since much of mash is implemented in Tcl, we needed a solution to the software management problem and thus adopted one of the object-oriented extensions to Tcl. We chose OTcl primarily because it requires no change to the Tcl core.


The Basics
In addition to the object APIs defined above, you will want to know the basic operational framework of the mash shell. You can think of mash simply as a extended Tcl interpreter, just like ''wish'' is a Tcl interepreter with the Tk extension for building graphical user-interfaces. Mash extends Tcl/Tk with an TclCL programming model and the set of multimedia networking objects defined above.

As with wish, you can run mash interactively. To do so, simply run mash without any arguments: 

        % mash

You will then get a new prompt at which you will be able to type commands in the Mash shell. 


Object Manipulation
Before you can invoke methods on an object according to the APIs defined above, you must first create the object. As with C++, a new object instance is created with the new command. The syntax is

        % new < class > < args > 

or  where class is the name of the OTcl/C++ class that defines the new object and args is an arbitrary number of arguments that are passed to the object constructor (i.e., the OTcl init method). The new command actually returns the name of a new Tcl procedure, which can then be called to invoke methods. That is, the creation of objects and their method invocations are naturally expressed as follows:

        % set object [new < class >]
        % $object invoke1
        % $object invoke2 arg1 arg2

If the object is a split Tcl/C++ object, the TclCL library automatically creates the C++ shadow object instance and binds it to the OTcl object instance.

Our convention for constructor arguments follows the OTcl convention, where a set of dashed arguments are mapped into a sequence of method calls. For example, if the arguments string is "-m1 a -m2 b c", then the method calls "m1 a" and "m2 b c" are invoked on the object upon its creation. That is, the following code

        % set object [new Foo -m1 a -m2 b c]

is equivalent to

        % set object [new Foo]
        % $object m1 a
        % $object m2 b c

Although this convention for object constructor argument processing is our currently accepted practice, quite a bit of old code uses an alternative practice where the arguments are actually caught and interpreted by one or more of the mash object constructors. Instead, we recommend that all the arguments be passed up to the default OTcl constructor (via "$self next $args" called from in the subclass' init method). The default constructor handles the interpretation and the dispatching of the dashed arguments. Another common practice that we now discourage is the exposure of instance variables. Instead, all instance variables should be queried and modified through a procedural interface.

As with other object-oriented programming languages, objects can be destroyed, in this case, with the delete command. The syntax is simply

        % delete < object >

where object is the name of the object to be deleted. For example, to delete the Foo object created above, you would simply say

        % delete $object

When the object is deleted the OTcl descructor method or methods are invoked as well as the C++ destructor in the case of OTcl/C++ split objects. The C++ destructor is called after all of the OTcl destructors have been called.


An Example

To illustrate object creation and manipulation, let's walk through the process of creating a simple IP network object. You create the core object as follows:

   % set net [new Network/IP]

As described above, the new command creates and returns the name of a command which can then be invoked to access the internals of the object. Each object has its own API, as documented above, To set the address, port and ttl (time-to-live) of the network object to 224.41.53.124, 23562, and 31 respectively, you would invoke: 

   % $net addr 224.2.53.124 
        % $net port 23562 
        % $net ttl 31

Equvilantly, the object could have been created as follows:

        % set net [new Network/IP -addr 224.2.53.124 -port 23562 -ttl 31]

You could also request information from the object. For instance, if you'd like to know what the address is of the network object, you would type: 

   % set a [$net addr]

Then the variable a then contains the string "224.2.53.124". 


Assembling the Scripts

One way to build a Mash tool is to write a monolithic script that is stored in a single file, which is then executed by the Mash interpreter. But this leads to a large and difficult to manage script and further precludes easy sharing of scripting code across tools. An alternative approach, which we've adopted, is to modularized the script into packages that can be mixed and matched with tool-dependent glue.

The question then is how do we manage the packages? One approach is to use the Tcl package concept, where modules with well-known names are loaded on demand from an installed repository (e.g., from /usr/local/lib/tcl). But with this model, the user is burdened with installing and maintaining auxiliary packages, and evolving versions can create subtle failures. Even with explicit version number checks, the user is forced to re-install packages, and potentially maintain multiple versions simultaneously, on an ad hoc basis. Instead, our approach is to simply string together packages using the Tcl "source" command to load each module explicitly from a master "main.tcl''. When a stable version of the tool is ready, we simply run a filter over main.tcl to collapse all of constituent source files into a monolithic script (which is never directly modified by the programmer). Then, we can simply distribute the mash interpreter and the each individual tool script and they will run all by themselves.

Of course, this is just our convention. You can easily diverge from this practice when you develop your own scripts since mash is a complete superset of Tcl.

All of the scripts for our tools reside in the tcl directory under the subdirectory named after the tool. There is a common subdirectory, and a few other utility directories, which contain Tcl scripts that are are shared amond the tools.

In each tool subdirectory there exists a file "main.tcl''. This file contains all the Tcl "source'' commands, which include the various Tcl files that comprise the tool's script. Note that the pathnames are relative to the top-level directory rather than the current one. Our Makefile includes rules for building each individual tool. To build vic, for example, simply run:

   % make vic

This command runs script in "tcl-expand.tcl'' on the file tcl/vic/main.tcl. This script recursively expands all the "source'' commands in that file to create a single, monolithic tcl script. Finally, the header file head.tcl is prepended to this output and the resulting script is the vic binary. Under Unix, the resulting script can be invoked directly from the command line due to a subtle trick borrowed from the Tcl distribution. At the top of each tool script, we include the following lines:

    #!/bin/sh
         # the exec restarts using tclsh which in turn ignores
         # the command because of this backslash: \
         exec mash "$0" -name TOOLNAME "$@"

The comment above explains the trick: The script is first invoked using the sh shell which then restarts the script using the mash interpreter. Tcl considers any line ending with a backslash to continue on the next line, thus the Tcl shell associates the exec command with the comment on the previous line, and proceeds to execute the body of the Tcl script. Finally, note that the Makefile rules substitute the actual tool's name with the string TOOLNAME as part of the script building process. If the ``-name'' argument is omitted, the mash interpreter still runs but the Tk option data base doesn't work and a number of other problems surface, often causing subtle and/or cryptic error messages.

Home | About | Users | Developers | Status | Resources | Top of Page

Webmaster
© Copyright 1999 - 2001 by the Regents of the University of California