## Darwin Streaming Server Source Code

## Developer Notes

Table of Contents

Building
Installation
Configuration and Testing

About the Source

Licensing

The Darwin Streaming Server is distributed under the terms of the Apple Public Source License. For more information, refer to the license terms at www.publicsource.apple.com. Note that the Apple Public Source License does not allow you to use the terms "QuickTime" or "QuickTime Streaming Server" in descriptions of products developed using Darwin Streaming Server open source code, nor use any Apple trademarks or logos associated with QuickTime and QuickTime Streaming Server.

Building

If you downloaded a binary package of Darwin Streaming Server, skip to the "Installing" section.

To build Darwin Streaming Server on UNIX platforms including MacOS X, type "./Buildit" from within the Darwin Streaming source directory. The script determines the current OS and hardware platform, and builds all of the targets for that platform: DarwinStreamingServer, PlaylistBroadcaster, qtpasswd, and dynamic modules included in the "StreamingServerModules" folder.

To build Darwin Streaming Server on Windows NT or Windows 2000, you must have a copy of Visual C++. There is a VC++ workspace file located inside the WinNTSupport directory. Once the workspace is open, from the Build menu select Batch Build.

Building the Installer

On OS X, at the top level of the source directory, type "./Buildit install dss_fat" to build for 32bit and 64bit ppc and intel processors or type "./Buildit install dss" to build an installer for the current processor only. An OS X installer package will be created in the source directory.

On Unix platforms, type "./Buildit install". A DarwinStreamingSrvr-Platform install directory and tar file will be created.

On Windows, after building using the WinNTSupport project, run the MakeZip.bat file inside WinNTSupport directory. A WinNTSupport\DarwinStreamingServer install directory will be created.

Adjusting the Mac OS X Installer

If you are building an installer for Mac OS X 10.4 you will need to change the installer's OS and Volume check script located inside the DarwinStreamingServer.pkg at DarwinStreamingServer.pkg/Contents/Resources/VolumeCheck.

You can simply remove the script to allow installs on any volume and OS or edit the file and change the OS version. Simply change the version number the script is checking.

Look for: my $REQUIRED_OS_VERS = "10.5.0";

Installing/b

<>

After building the installer, on OS X, double click the DarwinStreamignServer.pkg.

On Unix platforms, type ./Install from within the DarwinStreamingSrvr-Platform install directory.

On Windows, run the Install script from within the DarwinStreamingServer directory.

How to build your dynamic QTSS API modules

For building new dynamic QTSS API modules on Mac OS X, follow the instructions in the QTSS API developer documentation, "QTSSAPIDocs.pdf".

For platforms other that Mac OS X, your module must be built as a shared object, and it must include APIStubLib/QTSS_Private.cpp. This file is the "stub library" that all modules must link against.

On most UNIX platforms, building a shared object is like building any other executable, with the addition of one command-line argument to the linker. On Linux, the -shared option tells the linker that it is producing a shared object, on Solaris, the option is -G.

The dynamic QTSS API modules that come with Darwin Streaming Server each have a Makefile.POSIX makefile in their respective source directories. These makefiles execute when the Buildit script runs, and contain the make rules to make the dynamic module for each currently supported UNIX platform. It is easiest to use these existing makefiles as a template to copy and modify for your new QTSS API module.

Installation

The next step is to install and configure the server. On all platforms, the server reads its preferences from a config file. A default config file, streamingserver.xml, comes with both the source and binary packages. On Mac OS X, the server looks for the file in /Library/QuickTimeStreaming/Config. On Windows, the server looks for the file in "C:\Darwin Streaming Server". On UNIX platforms, the server looks for this file in /etc/streaming. If the streamingserver.xml file isn't available in the directory, the server will create one with the default configuration settings.

Once the server is built, you will have an executable called DarwinStreamingServer. The server can be run from the directory where it is built, or you can copy it to another location. On Mac OS X, the binary is called QuickTimeStreamingServer and will be placed in the build directory.

To run the server from the directory where it is compiled, just type ./DarwinStreamingServer.

Configuration and Testing

The server serves all streaming content out of its "media folder". By default, on Mac OS X, this media folder is located at /Library/QuickTimeStreaming/Movies. This path is one of the preferences in the config file. If you want your media folder to be located somewhere else, you must edit the "movie_folder" preference before starting the server. You can also set the movie folder in the web based administration interface. You can start administering by going to http://localhost:1220/ on your server.

Once you have a media folder, you can place streaming media into the folder. All QuickTime files must be "hinted" with QuickTime Player Pro or other QuickTime authoring applications before they can be streamed. Once the movie is hinted, copy the file to the streaming media folder on your server.

Sample movies (sample_100kbitmov, sample_300kbit.mov, sample_100kbit.mp4, sample_300kbit.mp4) are included in the package and in the source directory. The sample movies are already hinted, so you can place them into your media folder. From the QuickTime client, attempt to access those movie through an rtsp URL (e.g. rtsp://my.server.com/sample_100kbit.mov), and the server will stream that movie to the client.

In order to "reflect" a live broadcast, you must setup and start a broadcaster application, such as the QuickTime Broadcaster. The broadcaster produces an SDP file that describes the live broadcast. Place that SDP file into your media folder, access the URL from a QuickTime Client, and the server will "reflect" the live broadcast to the client. You can also do an automatic unicast from broadcasters that support this feature. You do not have to copy the SDP file to the media folder if you select this option.

Also included with the Darwin Streaming Server is StreamingLoadTool, a stress tool for testing the server. StreamingLoadTool realistically simulates many RTSP clients viewing a movie from the server. The tool offers many command-line options that can create different types of simulations. Typing ./StreamingLoadTool will print a description of all available options.

StreamingLoadTool will only work if there is a movie called "StreamingLoadTool.mov" in the root movie folder of the target server. This file must be a valid, hinted QuickTime movie.

For more information about authoring, hinting, and streaming QuickTime media, refer to the QuickTime Streaming Server documentation.

Q&A

Q. What platforms does the source compile and run on?

The source currently compiles and runs on Mac OS X. It can be ported to other platforms by modifying a handful of platform specific source files:

OSThread, OSCond, OSMutex: Implements threads, mutexes, and condition variables. The implementations provided work on MacOS X as well as any platform that supports pthreads.

OS: Includes some platform-specific code for getting the current time. Implementations provided work on MacOS X as well as any platform that supports gettimeofday.

Socket: This class is C++ wrapper for the sockets API. On MacOS X, this class uses a set of APIs collectively called the Event Queue for receiving events from sockets in non-blocking mode. For other platforms, an implementation of the Event Queue APIs using select() has been provided in ev.cpp. For more details on the Event Queue, see "What is the Event Queue?" in the FAQ section.

Q. What is the QTFile library?

One of the major features of the Darwin Streaming Server is the ability to serve hinted QuickTime files over RTSP and RTP. All of the code for parsing hinted QuickTime files has been abstracted into the QTFile library. Separating the code in this way keeps both parts much simpler: QTFile only deals with file parsing, the Darwin Streaming Server only deals with networking and protocols. The RTPFileModule in the server calls the QTFile library to retrieve packets and meta-data from hinted QuickTime files.

Q. What is the reflector, and how does it work?

The reflector allows an administrator to deliver live broadcasts to RTSP clients. The reflector is implemented as an RTP module, and the source code is entirely in RTPReflectorModule.h/.cpp, and ReflectorSession.h/.cpp.

When a QuickTime client wants to view a broadcast, it first connects to the Darwin Streaming Server reflector module and directs the module to look for a proper incoming broadcast. If the broadcast is found, the Darwin Streaming Server will then "reflect" the broadcast to the client. The following is a detailed description of how this works. Readers may want to familiarize themselves with SDP (Session Description Protocol), and IP multicast before continuing.

In order to reflect something, there must be a live broadcast available to reflect. A broadcast is a stream of RTP packets generated by an application or process external to the Darwin Streaming Server and typically run on a separate machine. In this discussion we will call the live stream generator the "Broadcaster". The Broadcaster converts a live media source (like a camera, or microphone, or whatever) into RTP packets. It sends the packets over UDP, to either a multicast or unicast destination address. Broadcasters will usually create .sdp files containing all the SDP (Session Description Protocol), information about this live presentation needed by the client and reflector.

Most importantly, the .sdp file contains the (destination) IP address and ports for the live presentation. The IP address can define a multicast or unicast connection for the client. QuickTime clients can read .sdp files directly and use them to connect directly to a Broadcaster. When the IP address in the .sdp file specifies a multicast address, the client will join the multicast provided there are multicast-aware routers between it and the Broadcaster. When the IP address is a unicast type, the client will connect when the .sdp destination IP address is the IP address of the client. This is because the Broadcaster is sending UDP packets directly to that machine!

In order to reflect the broadcast stream, the .sdp file created by the Broadcaster must be located on the server, and inside the server's media folder. Let's say that on our server, there's a .sdp file called "fish.sdp" located at the root of the media folder.

An RTSP client will connect using "rtsp://ourserver.com/fish",

After the .sdp file is found, the reflector parses the file to get the source IP address and ports for the live presentation. When the server then makes the connection, the same rules apply to the server as to a real client. This is because the .sdp specified server connection is simply a client of the live presentation. This means the IP address must specify a multicast address, or the IP address of the server itself.

Once the source address for the live presentation is located, the reflector binds some sockets to the specified ports. If the specified IP address is a multicast type, the reflector will join the multicast. At this point, those sockets will begin receiving all the data being sent by the Broadcaster.

The reflector module allows a multicast client to view the broadcast stream as a normal unicast stream coming from the Darwin Streaming Server. The .sdp file is rewritten on the fly by the reflector to erase the source IP address and port information, to hide the information from the client. Once a PLAY request is issued by the client, the reflector begins sending all incoming packets from the Broadcaster to the client.

As additional clients connect to the same live stream, the reflector increments refcounts and adds each new client to its stream tracking data structures. This efficiently allows each client to receive identical copies of all incoming packets from the Broadcaster.

When all clients have disconnected, the reflector closes the source UDP sockets, and deallocates all resources for that broadcast.

There is no limit on the number of unique live broadcasts that a single server can reflect, nor on the number of clients that can be connected to a single Reflection, apart from the overhead offile descriptor limitations, CPU, memory & bandwidth constraints. The CPU & memory consumed by a reflected stream is typically much less than normal locally stored media. Note: each unique live broadcast must be represented on the server by a unique .sdp file.

Q. What is the Event Queue?

The Event Queue is an extension to the sockets API that exists on Mac OS X. It consists of three API calls:

watchevent: Watch for events on a file descriptor (socket). waitevent: Wait for events on any of sockets (this is a blocking call, it only returns when there is an event pending). modwatch: When waitevent returns an event for a socket, that socket won't receive any new events until modwatch is called for that socket.

The use of these API calls is almost exclusively contained within Socket.cpp. This file contains the implementation of a thread object called SocketEventQueueThread. This thread blocks on waitevent and notifies the proper Task object (See "What Are Task Objects?") when an event is received.

For other UNIX platforms, an implementation of these three Event Queue API calls is provided in terms of select(). This implementation is contained in ev.cpp.

Q. How does the Darwin Streaming Server (DSS) employ threads?

DSS has four main threads managing its subsystems: a single connection thread for managing all connections, a short duration task thread for servicing tasks like rtp packet transmission, a long duration task thread for handling rtsp session requests and authentication, and an idle thread for time based tasks. DSS does not dedicate a thread per connection because the cost of servicing multiple connections would become prohibitively expensive when hundreds or thousands of connections are active. Typically connections last anywhere from 5 minutes to hours. To allow the server to scale into the thousands of connections, the Darwin Streaming Server uses asynchronous I/O wherever possible so a given thread will never block.

Q. What are Task objects?

Because the server is largely asynchronous, there needs to be a communication mechanism for events. For instance, when a socket used for an RTSP connection gets data, something has to be notified so that data can be processed. The Task object is a generalized mechanism for performing this communication.

Each Task object has two major methods: Signal and Run. Signal is called by the server to send an event to a Task object. Run is called to give time to the Task for processing the event. The goal of each Task object is to implement server functionality using small non-blocking time slices. Run is a pure virtual function that is called when a Task object has events to process. Inside the Run function, the Task object can call GetEvents to receive and automatically dequeue all its current and previously Signaled events. All Task functions are atomic: if a Task object calls GetEvents in its Run function, and is then Signaled before the Run function completes, the Run function will be called again for the new event after exiting the function. In fact, the Task"s Run function will be called repeatedly until the task object"s event queue has been cleared with GetEvents. Run functions are not re-entered during execution due to new signaled events.

This core concept of event triggered high performance Tasks is integrated into almost every subsystem in DSS. For instance, a Task object can be associated with a Socket object. If the Socket gets an event -- through a select() notification, or through the Mac OS X Event Queue (see "What is the Event Queue?") -- the corresponding Task object will be Signaled. In this case the body of the Run function will contain the code for processing whatever event was received on that Socket.

© 1999-2008 Apple Computer, Inc. All rights reserved. Apple, the Apple logo, Mac, Macintosh, PowerBook, Power Macintosh, and QuickTime are trademarks of Apple Computer, Inc., registered in the United States and other countries. iBook, iMac, and Power Mac are trademarks of Apple Computer, Inc. All other product names are trademarks or registered trademarks of their respective holders.