%Copyright (C) 2007-2015  Brian Langenberger
%This work is licensed under the
%Creative Commons Attribution-Share Alike 3.0 United States License.
%To view a copy of this license, visit
%http://creativecommons.org/licenses/by-sa/3.0/us/ or send a letter to
%Creative Commons,
%171 Second Street, Suite 300,
%San Francisco, California, 94105, USA.

\chapter{FreeDB}
Because compact discs do not usually contain metadata about
track names, album names and so forth, that information
must be retrieved from an external source.
FreeDB is a service which allows users to submit CD
metadata and to retrieve the metadata submitted by others.
Both actions require a category and a 32-bit disc ID number,
which combine to form a unique identifier for a particular CD.

%% The 32-bit disc ID is calculated from the total number of tracks,
%% the track offsets (in CD sectors) and the total length of the CD
%% (in seconds).

%% In the case of CD submission, the genre is decided by the submitter.
%% In the case of CD retrieval, the user must choose from a list
%% of possible choices when there is a collision between 32-bit disc ID
%% numbers.

%% The actual metadata is stored as XMCD files.

\begin{wrapfigure}[18]{r}{1.24in}
\includegraphics{figures/freedb/sequence.pdf}
\end{wrapfigure}
\section{Native Protocol}
FreeDB's native protocol runs as a service on TCP port 8880.
\begin{itemize}
\item After connecting, the client and server exchange a handshake using
the \texttt{hello} command.
The server will not do anything without this handshake.

\item Next the client changes to protocol level 6 with
the \texttt{proto} command.
This is necessary because only the highest protocol supports
UTF-8 text encoding.
Without this, any characters not in the Latin-1 set will not be
sent properly.

\item Once that is accomplished, the client should calculate the 32-bit
disc ID from the track information.

\item One then sends the 32-bit disc ID and additional disc information
to the server with the \texttt{query} command to retrieve a list of
matching disc IDs, genres and titles.
If there are multiple matches, the user must be prompted to
choose one of the matches.

\item When our match is known, the client uses the \texttt{read} command
to retrieve the actual XMCD data.

\item Finally, the \texttt{close} command is used to sever the connection
and complete the transaction.
\end{itemize}

\pagebreak

\subsection{the Disc ID}
\label{freedb:discid}
FreeDB uses a big-endian 32-bit disc ID to differentiate
on disc from another.

\begin{figure}[h]
\includegraphics{figures/freedb/discid.pdf}
\end{figure}
\par
\noindent
\VAR{Track Count} is self-explanatory.
\VAR{Total Length} is the total length of all the tracks, not
counting the initial 2 second lead-in.
\VAR{Offset Seconds Digit Sum} is the sum of the digits of all
the disc's track offsets, in seconds, modulo 255.
Remember to count the initial 2 second/150 frame lead-in when calculating
offsets.
\begin{table}[h]
\begin{tabular}{|c||r|r|r||r|r|r|}
\hline
Track & \multicolumn{3}{c||}{Length} & \multicolumn{3}{c|}{Offset} \\
Number & in M:SS & in seconds & in frames & in M:SS & in seconds & in frames \\
\hline
1 & 3:37 & 217 & 16340 & 0:02 & 2 & 150 \\
2 & 3:23 & 203 & 15294 & 3:39 & 219 & 16490 \\
3 & 3:37 & 217 & 16340 & 7:03 & 423 & 31784 \\
4 & 3:20 & 200 & 15045 & 10:41 & 641 & 48124 \\
\hline
\end{tabular}
\end{table}
\par
\noindent
In this example, \VAR{Track Count} is \textbf{4}.
\VAR{Total Length} is
$\frac{16340 + 15294 + 16340 + 15045}{75} = \textbf{840}$

There are 75 frames per second, and one must remember to count
fractions of seconds when calculating the total disc length.

The \VAR{Offset Seconds Digit Sum} is calculated by looking at the
\VAR{Offset in Seconds} column.
Those values are 2, 219, 423 and 641.
One must take all of those digits, add them, and mod 255 which works out to
$(2 + 2 + 1 + 9 + 4 + 2 + 3 + 6 + 4 + 1) \bmod 255 = \textbf{34}$

This means our three values are 34, 840 and 4.
In hexadecimal, they are 0x22, 0x0348 and 0x04.
Combining them into a single value yields 0x22034804.
Thus, our FreeDB disc ID is \texttt{22034804}

\clearpage

\subsection{Initial Greeting}
\begin{Verbatim}[frame=single,label=\textit{From Server},showspaces=true]
<code> <host> CDDBP server <version> ready at <datetime>
\end{Verbatim}
\begin{tabular}{rcl}
\multirow{5}{3em}{\texttt{<code>}}
& \texttt{200} & OK, reading/writing allowed \\
& \texttt{201} & OK, read-only \\
& \texttt{432} & No connections allowed: permission denied \\
& \texttt{433} & No connections allowed: X users allowed, Y currently active \\
& \texttt{434} & No connections allowed: system load too high \\
\texttt{<hostname>} & & the server's host name \\
\texttt{<version>} & & the server's version \\
\texttt{<datetime>} & & the current date and time
\end{tabular}

\subsection{Client-Server Handshake}
\begin{Verbatim}[frame=single,label=\textit{To Server},showspaces=true]
cddb hello <username> <hostname> <clientname> <version>
\end{Verbatim}
\begin{tabular}{rl}
\texttt{<username>} & login name of user \\
\texttt{<hostname>} & host name of client \\
\texttt{<clientname>} & name of client program \\
\texttt{<version>} & version of client program
\end{tabular}

\begin{Verbatim}[frame=single,label=\textit{From Server},showspaces=true]
<code> hello and welcome <username>@<hostname> running <client> <version>
\end{Verbatim}
\begin{tabular}{rcl}
\multirow{3}{3em}{\texttt{<code>}}
& \texttt{200} & handshake successful \\
& \texttt{402} & already shook hands \\
& \texttt{431} & handshake unsuccessful, closing connection \\
\texttt{<username>} & & login name of user \\
\texttt{<hostname>} & & host name of client \\
\texttt{<clientname>} & & name of client program \\
\texttt{<version>} & & version of client program
\end{tabular}

\subsection{Set Protocol Level}
\begin{Verbatim}[frame=single,label=\textit{To Server},showspaces=true]
proto [level]
\end{Verbatim}
\begin{tabular}{rl}
\texttt{[level]} & protocol level as integer (optional)
\end{tabular}
\begin{Verbatim}[frame=single,label=\textit{From Server},showspaces=true]
<code> CDDB protocol level: <current>, supported <supported>

OR

<code> OK, protocol version now:  <current>
\end{Verbatim}
\begin{tabular}{rcl}
\multirow{4}{3em}{\texttt{<code>}}
& \texttt{200} & displaying current protocol level \\
& \texttt{201} & protocol level set \\
& \texttt{501} & illegal protocol level \\
& \texttt{502} & protocol level already at \texttt{<current>} \\
\texttt{<current>} & & the current protocol level of this connection \\
\texttt{<supported>} & & the maximum supported protocol level
\end{tabular}

\pagebreak

\subsection{Query Database}
\begin{Verbatim}[frame=single,label=\textit{To Server},showspaces=true]
cddb query <disc_id> <track_count> <offset_1> <...> <offset_n> <seconds>
\end{Verbatim}
\begin{tabular}{rl}
\texttt{<disc\_id>} & 32-bit disc ID \\
\texttt{<track\_count>} & number of tracks in CD \\
\texttt{<offset>} & frame offset of each track \\
\texttt{<seconds>} & total length of CD in seconds
\end{tabular}
\begin{Verbatim}[frame=single,label=\textit{From Server},showspaces=true]
<code> <category> <disc_id> <disc_title>

OR

<code> close matches found
<category> <disc_id> <disc_title>
<category> <disc_id> <disc_title>
<...>
.

OR

<code> exact matches found
<category> <disc_id> <disc_title>
<category> <disc_id> <disc_title>
<...>
.
\end{Verbatim}
\begin{tabular}{rcl}
\multirow{6}{3em}{\texttt{<code>}}
& \texttt{200} & Found exact match \\
& \texttt{211} & Found inexact matches, list follows \\
& \texttt{202} & No match found \\
& \texttt{210} & Found exact matches, list follows \\
& \texttt{403} & Database entry corrupt \\
& \texttt{409} & no handshake \\
\texttt{<category>} & & category string \\
\texttt{<disc\_id>} & & 32-bit disc ID \\
\texttt{<disc\_title>} & & disc title string
\end{tabular}

\pagebreak

\subsection{Read XMCD Data}
\begin{Verbatim}[frame=single,label=\textit{To Server},showspaces=true]
cddb read <category> <disc_id>
\end{Verbatim}
\begin{tabular}{rl}
\texttt{<category>} & category string \\
\texttt{<disc\_id>} & 32-bit disc ID
\end{tabular}
\begin{Verbatim}[frame=single,label=\textit{From Server},showspaces=true]
<code> <category> <disc_id>
<XMCD_file_data>
<...>
.
\end{Verbatim}
\begin{tabular}{rcl}
\multirow{5}{3em}{\texttt{<code>}}
& \texttt{210} & XMCD data follows\\
& \texttt{401} & XMCD data not found\\
& \texttt{402} & server error\\
& \texttt{403} & database entry corrupt\\
& \texttt{409} & no handshake \\
\texttt{<category>} & & category string \\
\texttt{<disc\_id>} & & 32-bit disc ID \\
\end{tabular}

\subsection{Close Connection}
\begin{Verbatim}[frame=single,label=\textit{To Server},showspaces=true]
quit
\end{Verbatim}
\begin{Verbatim}[frame=single,label=\textit{From Server},showspaces=true]
<code> <hostname> <message>
\end{Verbatim}
\begin{tabular}{rcl}
\multirow{2}{3em}{\texttt{<code>}}
& \texttt{230} & Closing connection.  Goodbye.\\
& \texttt{530} & error, closing connection.\\
\texttt{<message>} & & exit message \\
\texttt{<hostname>} & & server's host name
\end{tabular}

\pagebreak

\section{Web Protocol}
FreeDB's web protocol runs as a service on HTTP port 80.
A web client POSTs data to a location, typically: \texttt{cddb/cddb.cgi}
and retrieves results.
This method is similar to the native protocol and the returned
data is identical.
However, since HTTP POST requests are stateless,
there are no separate \texttt{hello}, \texttt{proto} and \texttt{quit}
commands; these are issued along with the primary server command or are
implied.
\begin{table}[h]
\begin{tabular}{|r|l|}
\hline
key & value \\
\hline
\texttt{hello} &
\texttt{<username> <hostname> <clientname> <version>} \\
\texttt{proto} &
\texttt{<protocol>} \\
\texttt{cmd} &
\texttt{<command>} \\
\hline
\end{tabular}
\caption{POST arguments}
\end{table}
\par
\noindent
For example, to execute the \texttt{read} command on disc ID \texttt{AABBCCDD}
in the \texttt{soundtrack} category, one can POST the following string:
\begin{Verbatim}[frame=single]
cmd=read+soundtrack+aabbccdd&hello=username+hostname+audiotools+1.0&proto=6
\end{Verbatim}

\section{XMCD}

XMCD files are text files encoded either in UTF-8, ISO-8859-1 or
US-ASCII.
All begin with the string `\texttt{\# XMCD}'.
Lines are delimited by either the 0x0A character
or the 0x0D 0x0A character pair.
All lines must be less than 256 characters long,
including delimiters.
Blank lines are prohibited.
Lines that begin with the `\texttt{\#}' character are comments.
Curiously, the comments themselves are expected by FreeDB to contain
important information such as track offsets and disc length.
Fortunately, FreeDB clients can safely ignore such information
unless submitting a new disc entry.

What we are interested in are the \texttt{KEY=value} pairs in the
rest of the file.
\begin{table}[h]
{\relsize{-2}
\begin{tabular}{|r|l|}
\hline
key & value \\
\hline
\texttt{DISCID} & a comma-separated list of 32-bit disc IDs \\
\hline
\texttt{DTITLE} & an artist name and album name, separated by ` / ' \\
\hline
\texttt{DYEAR} & a 4 digit disc release year \\
\hline
\texttt{DGENRE} & the disc's FreeDB category string \\
\hline
\texttt{TITLE}\textbf{X} & the track title, or \\
& the track artist name and track title, separated by ` / ' \\
& \textbf{X} is an integer starting from 0 \\
\hline
\texttt{EXTD} & extended data about the disc \\
\hline
\texttt{EXTT}\textbf{X} & extended data about the track \\
& \textbf{X} is an integer starting from 0 \\
\hline
\texttt{PLAYORDER} & a comma-separated list of track numbers \\
\hline
\end{tabular}
}
\end{table}
\par
\noindent
Multiple identical keys should have their values
concatenated (minus the newline delimiter), which allows
a single key to have a value longer than the
256 characters line length.
