## Issue Tracking

https://ticket.leigh-co.com/projects/4e7a58ce-10f8-4420-8d92-4e7c97f5e7da

## Binaries

A binary distribution of Continuity mk4 with all the modules except the Oracle / Postgres / Dynamo connectors is available at smb://fs1/library/leighco-dist

## Compiling

### mk4
~~~
./configure
make
~~~

### mk5
~~~
cmake CMakeLists.txt
make
~~~

## Required Packages

~~~
dnf install -y libuuid libuuid-devel pcre pcre-devel
dnf install -y tcl tcl-devel tk tk-devel
~~~

## mod/m3 Internet radio

mod/m3 is a module written by Eric Lindvall for the Continuity server. mod/3m implements an Internat radio station supporting the Shoutcast protocol, which is detailed elsewhere. mod/m3 supports playing randomly from a list of MP3 files of various bitrates. It is not a requirement that all MP3 files played be of the same bitrate. (I do not recall if VBR MP3s are supported or not). mod/m3 is unique among shoutcast servers in that it ensures that all clients are hearing the same thing at the same time. If a client falls behind due to network or other latency, mod/m3 will skip that client ahead to the "present" time.

### Enduser Pages

mod/m3 supports dynamic HTML pages that allow endusers to interact with the radio station. It is possible to: list the state of the playlist, skip the song that is currently playing, see the current track information, and to schedule a mp3 to play even if it is not part of the playlist. This functionality is all implemented through TCL functions which are exposed through the mod/tcl module.

The content for these HTML pages have been lost to the mists of time, so it is currently a TBD to re-create them. The C functions for the TCL bindings are:

~~~
0000000000005b99 t m3_tcl_add_track
0000000000005a5d t m3_tcl_get_displayname
00000000000059df t m3_tcl_get_loser
0000000000005aa4 t m3_tcl_get_users
0000000000005966 T m3_tcl_init
0000000000005c96 t m3_tcl_reload_playlist
0000000000005b16 t m3_tcl_skip_track
~~~

The *m3_client* handler is written so that it will answer any request to the server from not a browser (based crudely on the user-agent). So there is no defined shoutcast URL, rather, any URL on the server not in the browser path will retrieve the stream. If the client is determined to be a browser, and it has requested something outside of the browser URL, then it will be redirected to the base browser URL. At that point, a different module like mod/site can pickup serving website content. This allows self-hosting the enduser HTML pages. 

If the HTML pages are created, then they must be served through mod/tcl & mod/site in the typical way. 

### Playlist File

The playlist file is apparently in M3U format but in reality a plaintext file listing the full paths to the MP3 files to stream is sufficient. Adding meta-data to this file is not productive. The file is loaded the first time a shoutcast client connects, or, when *m3_tcl_reload_playlist* is called. Of course, the server can always simply be restarted, but this will disconnect any connected shoutcast clients.

The playlist mechanic is such that when the playlist is loaded, it is randomized. mod/m3 will then play that shuffled playlist from top to bottom. When it gets to the end, it re-shuffles the playlist again. This ensures that, given uninterrupted operation, that every track will be heard at least once, and, also, that the order is always fresh, so endusers will not be able to predict what song comes after any given track. Contrast this to, for example, iTunes which seems to exhibit the behavior that it randomizes once when the playlist is modified, and then not again thereafter, so subsequent plays get the same shuffle order. 

### Configuration

The configuration takes place in two parts. Multiple radio stations may be configured on the same Continuity instance. The first piece of configuration is a <m3> block which is associated with a given site. This defines the general operation of the radio station, such as where to find the playlist file containing the MP3s to stream. The second piece of configuration is including the *m3_client* service handler.

mod/m3 uses the site_id attribute in the transaction block to correlate a request with a mod/m3 server instance, so this attribute must be set. The simplest way to do this is by using mod/site and the *siteFset_siteid* translation function. This can be seen in the working configuration example below.

### Example

~~~
<configuration>
    <continuity_config>
        <modules>
            <module>../lib/image</module>
	    <module>../lib/db</module>
            <module>../lib/cmd</module>
            <module>../lib/http</module>
            <module>../lib/site</module>
            <module>../lib/m3</module>
            <module>../lib/tcl</module>
        </modules>
        
        <pipelines>    
            <pipeline name="init">
	        <handler func="ipv4_openport">
                  <arg name="id">5</arg>
                  <arg name="port">80</arg>
                </handler>
                <handler func="httpFinit"></handler>
                <handler func="siteFinit"></handler>
                <handler func="ipv4_dispatcher">
                    <arg name="id">5</arg>
                    <arg name="port">80</arg>
                    <arg name="handler">httpFhandler</arg>
                </handler>
            </pipeline>
            
            <pipeline name="http_natr">
                <handler func="siteFset_siteid"></handler>
                <handler func="siteFip_restrict"></handler>
                <handler func="siteFset_setup_path"></handler>
                <handler func="siteFset_userdir">
                  <arg name="public_dir">Sites</arg>
                </handler>
                <handler func="siteFfind_index">
                    <arg name="exts">index.html</arg>
                </handler>


            </pipeline>
            
            <pipeline name="http_mime">
            </pipeline>
            
            <pipeline name="http_srvc">
            <handler func="m3_client"></handler>
            </pipeline>
            
            <pipeline name="http_log">
            </pipeline>
        </pipelines>
    </continuity_config>
    
    <modsite_config>
        <global>
            <logroot>/tmp</logroot>
        </global>

        <site id="_default">
            <docroot>/var/www/html</docroot>
      <m3 mountpoint="/">
          <playlist>/opt/music/m3.m3u</playlist>
          <browserUrl>/radio/</browserUrl>
          <shoutcastMetadata>
              <title>LEIGH&CO RADIO</title>
              <url>m3.leigh-co.com/radio/currently_playing.html</url>
         </shoutcastMetadata>
      </m3>
        </site>
        
        <mimetypes>
            <mimetype ext="ai">application/postscript</mimetype>
            <mimetype ext="aif">audio/x-aiff</mimetype>
            <mimetype ext="aifc">audio/x-aiff</mimetype>
            <mimetype ext="aiff">audio/x-aiff</mimetype>
            <mimetype ext="aim">application/x-aim</mimetype>
            <mimetype ext="asd">application/astound</mimetype>
            <mimetype ext="asp">application/x-asap</mimetype>
            <mimetype ext="au">audio/basic</mimetype>
            <mimetype ext="avi">video/msvideo</mimetype>
            <mimetype ext="bin">application/octet-stream</mimetype>
            <mimetype ext="bmp">image/bmp</mimetype>
            <mimetype ext="cdf">application/x-netcdf</mimetype>
            <mimetype ext="cgi">internal/cgi</mimetype>
            <mimetype ext="ckl">application/x-fortezza-ckl</mimetype>
            <mimetype ext="class">application/java-vm</mimetype>
            <mimetype ext="cpio">application/x-cpio</mimetype>
            <mimetype ext="crd">application/x-mscardfile</mimetype>
            <mimetype ext="crl">application/x-pkcs7-crl</mimetype>
            <mimetype ext="csh">application/x-csh</mimetype>
            <mimetype ext="css">text/css</mimetype>
            <mimetype ext="doc">application/msword</mimetype>
            <mimetype ext="dot">application/x-dot</mimetype>
            <mimetype ext="dwf">drawing/x-dwf</mimetype>
            <mimetype ext="dwg">image/vng</mimetype>
            <mimetype ext="dyn">dynamo-internal/template</mimetype>
            <mimetype ext="dynjava">dynamo-internal/dynjava</mimetype>
            <mimetype ext="enc">application/pre-encrypted</mimetype>
            <mimetype ext="eps">application/postscript</mimetype>
            <mimetype ext="es">audio/echospeech</mimetype>
            <mimetype ext="esl">audio/echospeech</mimetype>
            <mimetype ext="etc">application/x-earthtime</mimetype>
            <mimetype ext="etx">text/x-setext</mimetype>
            <mimetype ext="evy">application/x-envoy</mimetype>
            <mimetype ext="fif">image/fif</mimetype>
            <mimetype ext="fm">application/x-maker</mimetype>
            <mimetype ext="fvi">video/isivideo</mimetype>
            <mimetype ext="gif">image/gif</mimetype>
            <mimetype ext="gtar">application/x-gtar</mimetype>
            <mimetype ext="hdf">application/x-hdf</mimetype>
            <mimetype ext="hlp">application/winhlp</mimetype>
            <mimetype ext="hqx">application/mac-binhex40</mimetype>
            <mimetype ext="html">text/html</mimetype>
            <mimetype ext="htm">text/html</mimetype>
            <mimetype ext="ice">x-conference/x-cooltalk</mimetype>
            <mimetype ext="ief">image/ief</mimetype>
            <mimetype ext="ifs">image/ifs</mimetype>
            <mimetype ext="inc">internal/php4</mimetype>
            <mimetype ext="ins">application/x-NET-Install</mimetype>
            <mimetype ext="jar">application/java-archive</mimetype>
            <mimetype ext="jfif">image/jpeg</mimetype>
            <mimetype ext="jhtm">dynamo-internal/html</mimetype>
            <mimetype ext="jhtml">dynamo-internal/html</mimetype>
            <mimetype ext="jpeg">image/jpeg</mimetype>
            <mimetype ext="jpe">image/jpeg</mimetype>
            <mimetype ext="jpg">image/jpeg</mimetype>
            <mimetype ext="js">application/x-javascript</mimetype>
            <mimetype ext="jsc">application/x-javascript-config</mimetype>
            <mimetype ext="jsu">application/x-javascript;charset=UTF</mimetype>
            <mimetype ext="jtext">dynamo-internal/plain</mimetype>
            <mimetype ext="jtxt">dynamo-internal/plain</mimetype>
            <mimetype ext="lam">audio/x-liveaudio</mimetype>
            <mimetype ext="latex">application/x-latex</mimetype>
            <mimetype ext="lcc">application/fastman</mimetype>
            <mimetype ext="m13">application/x-msmediaview</mimetype>
            <mimetype ext="m14">application/x-msmediaview</mimetype>
            <mimetype ext="man">application/x-troff-man</mimetype>
            <mimetype ext="map">dynamo-internal/map</mimetype>
            <mimetype ext="mbd">application/mbedlet</mimetype>
            <mimetype ext="mdb">application/x-msaccess</mimetype>
            <mimetype ext="me">application/x-troff-me</mimetype>
            <mimetype ext="mi">application/x-mif</mimetype>  
            <mimetype ext="midi">audio/mid</mimetype>
            <mimetype ext="midi">audio/midi</mimetype>  
            <mimetype ext="mif">application/x-mif</mimetype>
            <mimetype ext="mny">application/x-msmoney</mimetype>
            <mimetype ext="moc">application/x-mocha</mimetype> 
            <mimetype ext="mocha">application/x-mocha</mimetype>
            <mimetype ext="moov">video/quicktime</mimetype>
            <mimetype ext="movie">video/x-sgi-movie</mimetype>  
            <mimetype ext="mov">video/quicktime</mimetype>
            <mimetype ext="mp2v">video/x-mpeg2</mimetype>
            <mimetype ext="mpeg">video/mpeg</mimetype>
            <mimetype ext="mpegv">video/mpeg</mimetype>
            <mimetype ext="mpe">video/mpeg</mimetype>
            <mimetype ext="mpg">video/mpeg</mimetype>
            <mimetype ext="mpv2">video/x-mpeg2</mimetype>   
            <mimetype ext="mpv">video/mpeg</mimetype>   
            <mimetype ext="ms">application/x-troff-ms</mimetype>
            <mimetype ext="nc">application/x-netcdf</mimetype>
            <mimetype ext="oda">application/oda</mimetype>
            <mimetype ext="pac">audio/x-pac</mimetype>
            <mimetype ext="pae">audio/x-epac</mimetype>
            <mimetype ext="pbm">image/x-portable-bitmap</mimetype>
            <mimetype ext="pcd">image/x-photo-cd</mimetype>
            <mimetype ext="pdf">application/pdf</mimetype>
            <mimetype ext="pgm">image/x-portable-graymap</mimetype>
            <mimetype ext="php">internal/php4</mimetype>
            <mimetype ext="pjpeg">image/jpeg</mimetype>
            <mimetype ext="pjp">image/jpeg</mimetype>
            <mimetype ext="pl">application/x-pl</mimetype>
            <mimetype ext="png">image/png</mimetype>
            <mimetype ext="pnm">image/x-portable-anymap</mimetype>
            <mimetype ext="pot">application/vnd.ms-powerpoint</mimetype>
            <mimetype ext="ppm">image/x-portable_pixmap</mimetype>
            <mimetype ext="pps">application/vnd.ms-powerpoint</mimetype>
            <mimetype ext="ppt">application/vnd.ms-powerpoint</mimetype>
            <mimetype ext="proxy">application/x-ns-proxy-autoconfig</mimetype>
            <mimetype ext="ps">application/postscript</mimetype>  
            <mimetype ext="pub">application/x-mspublisher</mimetype>
            <mimetype ext="qt">video/quicktime</mimetype>
            <mimetype ext="ra">audio/x-pn-realaudio</mimetype>
            <mimetype ext="ram">audio/x-pn-realaudio</mimetype>
            <mimetype ext="ras">image/x-cmu-raster</mimetype>
            <mimetype ext="rgb">image/x-rgb</mimetype>
            <mimetype ext="roff">application/x-troff</mimetype> 
            <mimetype ext="rtf">application/msword</mimetype>
            <mimetype ext="rtx">text/richtext</mimetype>
            <mimetype ext="scd">application/x-msschedule</mimetype>
            <mimetype ext="ser">application/java-serialized-object</mimetype>
            <mimetype ext="sh">application/x-sh</mimetype>
            <mimetype ext="shar">application/x-shar</mimetype>
            <mimetype ext="sit">application/x-stuffit</mimetype>
            <mimetype ext="slc">x-salsa</mimetype>
            <mimetype ext="smp">application/studiom</mimetype>   
            <mimetype ext="sn">application/astround</mimetype>
            <mimetype ext="snd">audio/basic</mimetype>
            <mimetype ext="spr">application/x-sprite</mimetype>
            <mimetype ext="sprite">application/x-sprite</mimetype>  
            <mimetype ext="src">application/x-wais-source</mimetype>
            <mimetype ext="svf">image/vng</mimetype>
            <mimetype ext="svr">x-world/x-svr</mimetype>
            <mimetype ext="talk">text/x-speech</mimetype>
            <mimetype ext="t">application/x-troff</mimetype>
            <mimetype ext="tar">application/x-tar</mimetype>
            <mimetype ext="tbp">application/x-timbuktu</mimetype>
            <mimetype ext="tbt">application/timbuktu</mimetype>
            <mimetype ext="tcl">internal/tcl</mimetype> 
            <mimetype ext="tex">application/x-tex</mimetype>
            <mimetype ext="texi">application/x-texinfo</mimetype>
            <mimetype ext="texinfo">application/x-texinfo</mimetype>
            <mimetype ext="tiff">image/tiff</mimetype>
            <mimetype ext="tif">image/tiff</mimetype>
            <mimetype ext="tki">application/x-tkined</mimetype> 
            <mimetype ext="tkined">application/x-tkined</mimetype>
            <mimetype ext="tr">application/x-troff</mimetype>
            <mimetype ext="trm">application/x-msterminal</mimetype>
            <mimetype ext="tsv">text/tab-seperated-values</mimetype>
            <mimetype ext="vbs">video/mpeg</mimetype>
            <mimetype ext="vivo">video/vivo</mimetype>
            <mimetype ext="viv">video/vivo</mimetype>
            <mimetype ext="vrt">x-world/x-vrt</mimetype>
            <mimetype ext="wav">audio/x-wav</mimetype>
            <mimetype ext="wiz">application/msword</mimetype> 
            <mimetype ext="wmf">application/x-msmetafile</mimetype>
            <mimetype ext="wrl">x-world/x-vrml</mimetype>
            <mimetype ext="wv">video/wavelet</mimetype>
            <mimetype ext="xbm">image/x-xbitmap</mimetype>
            <mimetype ext="xla">application/vnd.ms-excel</mimetype>
            <mimetype ext="xlc">application/vnd.ms-excel</mimetype>
            <mimetype ext="xlm">application/vnd.ms-excel</mimetype>
            <mimetype ext="xls">application/vnd.ms-excel</mimetype>
            <mimetype ext="xlt">application/vnd.ms-excel</mimetype>
            <mimetype ext="xlw">application/vnd.ms-excel</mimetype>
            <mimetype ext="xpm">image/x-xpixmap</mimetype>
            <mimetype ext="xwd">image/x-xwindowdump</mimetype>
            <mimetype ext="zip">application/zip</mimetype>
        </mimetypes>         
    </modsite_config>
</configuration>
~~~
