OPENdj DJServer Internal Design Document

By Jonathan Cobb
(C) 2001 DAX Interactive, LLC

This document is an introduction to the internal design of the DJServer. The DJServer implements the server-side of the OPENdj Streaming Protocol.

There's a lot that's not covered here, but this should be enough to get you going if you're interested in picking apart the server internals.

Class Diagram:


DJServer

The DJServer is the head-honcho class. DJServer's runtime behavior is:

  1. Initialize the database connection (the PStore class).
  2. Initialize the audio server (the AudioServer class).
  3. Go into a socket-accept loop, listening for ODSP connections. When a connection comes in, the DJServer instantiates a DJConnection object to handle it.

DJConnection

Each instance of the DJConnection class handles the details of a single client connection to the DJServer. Since ODSP is a request/response oriented protocol, once a DJConnection is created, its runtime behavior is very simple: receive a request from the client, do some server-side processing, return a response.

The DJConnection's implementation of the ODSP protocol looks like this:
ODSP Request Server processing
AUTH Compare email and password to values in the database. If a valid login and password are supplied, change state to "authorized" and return response. If login/password is invalid, return an error response.
GETAUDIOSERVERINFO The audio server info (IP, port, password, max bitrate) is all stored in a configuration file read by the Config class at startup. The DJConnection's response to a GETAUDIOSERVERINFO simply echoes these values in the format proscribed by ODSP.
GETCHANNELTIMES Query the database for broadcast times for the current DJ. Return the appropriate ODSP response.
BROADCAST Ask the AudioServer if the DJ can start broadcasting. If the AudioServer tells us that the DJ should be on the air NOW, return a GO response immediately. Otherwise, return a DELAY response indicating how long the client should wait before retrying the BROADCAST request.
GETSHOWSTATS While a broadcast is in progress, the AudioChannel class is responsible for collecting the statistics about how many listeners are tuned in to each channel. It stores these stats in the database. When a client issues the GETSHOWSTATS request, all we do is query the database for show statistics and return the appropriate ODSP response.
GETGENRES Queries the database for the list of genres, returns the list as an ODSP response.
GETMOODS Queries the database for the list of moods, returns the list as an ODSP response.
UPDATESHOWMETADATA Parse the request, tell the AudioServer to update the meta data associated with the current broadcast. The AudioServer in turn delegates the request to the AudioChannel responsible for the channel that the DJ is broadcasting on. The AudioChannel then does some basic security checks and then updates the meta data in the database.
WAITFOREXIT Ask the AudioServer if the DJ can stop broadcasting. If the AudioServer tells us that the DJ should stop broadcasting, send a CLOSENOW response. Otherwise, send a DELAY response indicating when the client should retry the WAITFOREXIT request.
DISCONNECT Send a BYE response, close the connection.

AudioServer

The AudioServer provides a layer of abstraction over the Icecast server. AudioChannels and DJConnections talk to the AudioServer when they need to access audio-server related functions, for example to negotiate connections and disconnections for client encoders. The AudioServer is started by the DJServer when it initializes. When the AudioServer starts up, it creates an AudioChannel object for each channel in the system.

AudioChannel

Each instance of the AudioChannel class controls a single channel. The AudioChannel is responsible for controlling access to an Icecast mount point that reflects what has actually been scheduled on the channel.

PStore

Provides a layer of abstraction over the database. All database access goes through the PStore class.


Copyright 2001 DAX Interactive, LLC.
$Author: jonathan $
$Revision: 1.1.1.1 $