Articles Archive
Articles Search
Director Wiki
 

Multiuser Presentations in Director

March 22, 2002
by Chris Griffith

Ever wonder what you really could use the Shockwave Multiuser Server (SMUS, or just MUS) for? How many of us have the opportunity to author the last Everquest for our clients? I recently used the MUS for a multi-system networked presentation. In fact we used the MUS to win the contract.

Little Background on MUS

Now on version 3.0, this mostly-free application has been shipping with Director for a few years. I say it is mostly free, since you are limited to the number of clients you can serve before you have to pay Macromedia. It runs on either Macintosh or Windows (for an alternative that runs on Linux, as well as FreeBSD and Mac OS X, check out Tabuleiro's Nebulae MultiUser Server) and is fairly easy to install and configure for basic uses. Just locate your Director CD and the installer. After it has been installed, just launch it. You will see are screen like this:

It looks almost the same on either platform. The one thing you do want to do is get the IP address for this machine, you will need it later. You can do this by selecting server from the Status menu. Of course, since we're talking about a multiuser server here, you're going to need to try it out on a network to really get a feel for how it works, although you can run and perform some tests with MUS on a single, un-networked machine.

How the MUS Won the Day

We were demonstrating the basic capabilities of Director to a potential client (something we seem to do all the time) for a multi-system networked demonstration to DARPA (Defense Advanced Research Projects Agency, the folks who, in part, built the Internet ). I had used the MUS on another project, so I had some basic MUS code ready to use. Our plan was to create a simple 5-7-screen "PowerPoint"-like presentation outlining Director's features, our past projects, etc. The hook was we were going to show this presentation simultaneously on six systems.

The basic outline of the effort was simple: Each client would log into the MUS, receive forward, back or home messages to control the presentation. (And the entire Apollo space program could be summed up as build rocket, go to the moon and back ).

Logging on to the MUS

The first step is letting the MUS know you are there. This is done by this bit of code:

on connectToMU

  global gMUXtra
  global gNetworkEnabled

  gMUXtra = VOID
  gMUXtra = new (xtra"MultiUser")
  gMUServerIP = "128.128.128.128"
  gSystemName = "Presentation1"

  ------
  -- Connect
  -----
  errCode = gMUXtra.connectToNetServe r(gSystemName, "", gMUServerIP, 1626, "PowerPoint")
  if errCode <> 0 then
    Alert "connectToNetServer Error:" & gMUXtra.getNetErrorString (errCode)
    gNetworkEnabled = 0
  else
    gNetworkEnabled = 1
  end if

end

You can copy this script into a movie and try to run it, just change the dummy IP address to the IP address of your MUS. When you run it the MUS screen will now look like this

You will see that two things happened. First, the MUS created a movie named PowerPoint. This allows the MUS to manage several different movies on the same system. We can ignore this feature for now, but if you are planning to build a more complex system, you will need to learn more about this feature and hosting multiple MUS movies (they're not the same thing as Director movies). The second item you will notice is that it informed us that the client, Presentation1 had connected to the movie PowerPoint. This is how you can monitor each of the systems logging on.

But wait, didn't we want the same Director movie running on all the machines? What do I do if the IP address of the MUS changes? We don't want to rebuild all those projectors every time.

The easiest solution is to use the lingo.ini file. You can include a custom lingo.ini file with each projector. For those who have never used lingo.ini, it is a text file that can be placed at the same level as your projector, and is read automatically at startup. So you don't need to use something like the FileIO Xtra to read a file for information. In fact, the lingo.ini file uses a special Lingo handler, on startup. (It's not in the Lingo dictionary, so don't bother). So we can define both the user and the IP address of the MUS in the file without having to create a projector for every system. The lingo.ini file for this project would look like:

on startup
   global gMUServerIP
   global gSystemName
   gMUServerIP = "128.128.128.128"
   gSystemName = "Control"
end

Just remember the gSystemName must be different on every system that will connect to the server. In fact, we will use this feature in a moment. Let's return to the connection script. First let's change both the user and MUS address variables from local variables to the globals we have defined in the lingo.ini file. I've added a little error checking, just in case something goes wrong. The new connection script now looks like:

on connectToMU

  global gMUXtra
  global gNetworkEnabled
  global gSystemName
  global gMUServerIP

  gMUXtra = VOID
  gMUXtra = new (xtra "MultiUser")
  if voidP (gMUServerIP) then gMUServerIP = "128.128.128.128"
  if voidP (gSystemName) then gSystemName = "Presentation1"
  ------
  -- Connect
  -----
  errCode = gMUXtra.connectToNetServer (gSystemName, "", gMUServerIP, 1626, "PowerPoint")
  if errCode <> 0 then
    Alert "connectToNetServer Error:" & gMUXtra.getNetErrorString (errCode)
    gNetworkEnabled = 0
  else
    gNetworkEnabled = 1
  end if
end

So now we could build a projector, place a different lingo.ini file with each copy on the different machines and have either a button that calls connectToMU or place it in the startMovie handler. But, we still have not added the ability to communicate between the systems.

Communication with MUS

This was the one thing that caught me off guard. I had a model in my head that I would make a connection to the MUS, then create my message callback after that. In fact you do the opposite. You set up your callbacks then make the connection to the MUS. The callback handler is sent a message whenever the instance of the Multiuser Xtra generates some sort of event.

Setting up callback is fairly straightforward. Here is the section of code that establishes the callback that we will use:

  -----
  -- slide Control
  ------
  errCode = gMUXtra.setNetMessageHandler (#slideControlHandler, script "Connection Script"," slide control message","")

  if errCode <> 0 then
    Alert "setNetMessageHandler Error Code:" & gMUXtra.getNetErrorString (errCode)
  end if

What does all this mean? All we have done is tell the instance of the Multiuser Xtra is, if you get a message with "slide control message" as the subject, then pass all the information to the handler slideControlHandler in the script cast named Connection Script. You can create as many callbacks as you need for your project.

Let's examine the slideControlHandler script.

on slideControlHandler
  global gMUXtra
  global gSystemName

  newMessage = gMUXtra.getNetMessage ()

  member ("Output").text = ">>" && string (newMessage)
  errCode = newMessage.errorCode

  if errCode <> 0 then
    put "slideControlHandler Error " & gMUXtra.getNetErrorString (errCode)
  else
    theData = newMessage.content
    
    theSlideCommand = theData.SlideCommand
 
    case theSlideCommand of
      #Home: go frame 1
      #Next: go marker (1)
      #Prev: go marker (-1)
    end case
    
  end if

end

The first step is to actually get the MUS message by using the getNetMessage function. This function returns a property list of various items, including any error codes, a timestamp, a subject, and content you may include. To learn more about this message, you read the MUS documentation. There you can learn about using the MUS to send other Director objects including images and audio. But for our needs we will be just sending a simple property list.

The first thing to check after receiving a message is to examine it for any error codes. This is the most basic error handling one could have. Since we were on a closed network, and in a relatively controlled environment, we did not have to build anything robust. However, one could construct a system that after a message is sent creates an object which waits for a message back from all the receivers, and if it does not get a reply, resends the message.

The next portion of the code is where we parse out the data from the MUS message. This is contained in the content portion of the MUS message. This data is then sent through a case statement to control the presentation. A good exercise would be to expand this handle to allow you to advance to any marker (i.e. slide) in the presentation.

So we now have the code in place to connect to the MUS, and handle the messages to control our presentation. Now we need to send them.

Sending MUS Messages

How are you going to tell the projector that this is the system that the presenter is using and not allow others to control the presentation? Here is where the lingo.ini file will help you again.

On the presenter's; computer, change the gSystemName value to something like "Presenter". Our control code will check the gSystemName variable and only allow the controls to work on the presenter machine. For this example, we are going to control the presentation using the arrow keys and the mouse button. The movie script to do this looks like:

on mouseUp me
  global gSystemName

  if gSystemName = "Presenter " then
     sendSlideControlMessage [#SlideCommand: #Next]
  end if
end

on keyDown
  global gSystemName

  if gSystemName = "Presenter " then
    case (the keyCode) of
      123: sendSlideControlMessage [#SlideCommand: #Prev]
      126: sendSlideControlMessage [#SlideCommand: #Home]
      124: sendSlideControlMessage [#SlideCommand: #Next]
    end case
  end if
end

Each of the controls just sends a parameter to our MU message sending script, sendSlideControlMessage. Let's look at this script:

on sendSlideControlMessage theData
  global gMUXtra
  global gNetworkEnabled

  -----
  -- example data struct
  -- theData = [#SlideCommand:#Prev]
  -----

  if gNetworkEnabled then
    if not (voidP (theData)) then
      gMUXtra.sendNetMessage (" / at / AllUsers", "slide control message", theData )
    end if
  end if

end

That is all there is to it. If we breakdown the sendNetMessage call, there are three basic parameters: who you are sending the message to (in this case all the clients), the subject of the message ("slide control message") and the content of the message (a property list called theData in this case).

So with this basic framework you can construct a simple Multiuser application. I have included the source code for the completed presentation. To run the demonstration do the following:

  1. Install the MU and launch it. Get the IP address of the machine
  2. Create a projector from the source. Make sure you include the MU Xtra in either the Xtras folder or in the projector.
  3. Create a lingo.ini file containing the startup handler (as shown above) to reflect your MUS's IP address
  4. Place the projector,the Xtras folder, and the lingo.ini file on all the machines you want. Remember, for each machine, create a unique user name, but name one "Presenter" or you won't be able to control the presentation
  5. Launch each projector. You will see each client log on to the Multiuser Server. Once all the clients have logged on, you will be able to control all the clients from one system.

A Final Note

You may have noticed that we sent the message to / at / Allusers, but you can send the messages to one specific client or a subgroup of clients. In the actual demonstration that we built this is exactly what we did. A system was placed behind the curtain that allowed us to control the other eleven systems used in the presentation. Each of these systems was displaying different screens, and would advance at different points during the presentation.

 

Here is a screen shot of the controlling interface. I never made it look very pretty. The demo was controlled by the button on the left side of the screen. We also had controls to directly advance any of the other systems. One of the last touches we added was to check which systems had logged on (the actual Lingo is

gMUXtra.sendNetMessage ("system.group.getUsers", "anysubject", " / at / allUsers"))

This was done just in case one went down or was not available. The software would adjust the for this and not try to send message to that client.

I hope this article has given you some help and insight in understanding how you can use the Multiuser Server in your next Director project.

Sample Director 8 files are available in ZIP and SIT archives.

All colorized Lingo code samples have been processed by Dave Mennenoh's brilliant HTMLingo Xtra, available from his site at http://www.crackconspiracy.com/~davem/

Starting with a MacSE (now a MacAquarium), Chris has been working with Director since version 3 and continues to explore the uses of multimedia. He is currently an engineer at Pacific Science & Engineering Group, Inc., a company specializing in human factors research and development. He has developed DVD, CD, and Shockwave projects for such clients as Presto Studios, The Coca-Cola Company, J. Walter Thompson, and the United States Marines Corp. Chris can be reached at cgriffith@pacific-science.com when he is not kayaking in the Pacific Ocean or playing with his 6 year old twins.

Copyright 1997-2017, Director Online. Article content copyright by respective authors.