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:
- Install the MU and launch it. Get the IP address of the machine
- Create a projector from the source. Make sure you include the MU Xtra in either the Xtras folder or in the projector.
- Create a lingo.ini file containing the startup handler (as shown above) to reflect your MUS's IP address
- 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
- 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/
Copyright 1997-2024, Director Online. Article content copyright by respective authors.