<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>streaming &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/tag/streaming/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Mon, 02 Nov 2020 13:54:02 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>General: How to stream/broadcast from your phone</title>
		<link>https://blog.andreev.it/2020/05/general-how-to-stream-broadcast-from-your-phone/</link>
					<comments>https://blog.andreev.it/2020/05/general-how-to-stream-broadcast-from-your-phone/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 03 May 2020 13:47:48 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[broadcast]]></category>
		<category><![CDATA[Larix]]></category>
		<category><![CDATA[SRT]]></category>
		<category><![CDATA[streaming]]></category>
		<category><![CDATA[VLC]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=6678</guid>

					<description><![CDATA[In this short article I&#8217;ll describe briefly how to stream/broadcast from your phone&#8217;s camera&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this short article I&#8217;ll describe briefly how to stream/broadcast from your phone&#8217;s camera to the world. In order to do that, you&#8217;ll need the <strong>Larix Broadcaster</strong> app installed on your phone, you will need a server with a public IP and a <strong>Haivision Media Gateway</strong> installed and for the end users, they&#8217;ll need standard <strong>VLC Player</strong> install.<br />
The Larix Broadcaster app and the VLC player are free, but Haivision Media Gateway is not. In addition, if you have your own server and want to install it as a VM, you&#8217;ll have to contact the vendor directly. I&#8217;ll use a much easier option and host it in AWS where it comes as a template from the <a href="https://aws.amazon.com/marketplace/pp/Haivision-Haivision-Media-Gateway-PAYG/B014VA1JZ4" rel="noopener noreferrer" target="_blank">AWS Marketplace</a>.</p>
<h1>Haivision Media Gateway in AWS</h1>
<p>In AWS, launch a new instance from the AWS Marketplace and search for SRT. You&#8217;ll see several options(SRT Gateway vs. Media Gateway and BYOL as PAYG license). I&#8217;ll choose Pay-as-You-Go Media Gateway.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-01.png"><img fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-01.png" alt="" width="1357" height="191" class="aligncenter size-full wp-image-6680" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-01.png 1357w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-300x42.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-1024x144.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-768x108.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-1170x165.png 1170w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-585x82.png 585w" sizes="(max-width: 1357px) 100vw, 1357px" /></a><br />
As you can see, the software is not that cheap and you pay as much as you used. So if you are not streaming, just shut down the instance. Another important thing is the size of the instance, how much horse power you need. Is it 2 CPUs, 4 CPUs, 8? Well, nobody knows your needs, but it also depends on what type of stream are you sending, is it going to be a low-res or 1080p, how many users will consume that stream, etc. I strongly suggest that you go over this <a href="https://doc.haivision.com/additional-resources/srt-deployment-guide" rel="noopener noreferrer" target="_blank">document</a>. It describes how to size your environment and it gives you practical guidance on how to configure the Media Gateway. It&#8217; not a necessary read to continue with this post, but it&#8217;s strongly recommended once you have everything up and running.<br />
OK, in my case I&#8217;ll go with a t3.medium instance which is 2 CPUs and 4GB RAM. Create the instance as you normally do, make sure you have a public IP and the ports that are recommended in the security group given are open (22, 80 and 443). Once the instance boots up log with the default username <strong>haiadmin </strong>and the password is your instance id which is <strong>i-0123something</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-02.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-02.png" alt="" width="468" height="488" class="aligncenter size-full wp-image-6681" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-02.png 468w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-02-288x300.png 288w" sizes="(max-width: 468px) 100vw, 468px" /></a><br />
I won&#8217;t go into details what each option does and what each keyword means, I&#8217;ll just guide you through creating a route for you to be able to broadcast. So, from the screen that you see, click on the button to add a route.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-03.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-03.png" alt="" width="1061" height="137" class="aligncenter size-full wp-image-6682" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-03.png 1061w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-300x39.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-1024x132.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-768x99.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-585x76.png 585w" sizes="(max-width: 1061px) 100vw, 1061px" /></a><br />
These are my parameters. For the <strong>Route Name</strong>, enter a description and make sure the checkmark is checked for Start Route. Further down, enter a description for the <strong>Source Name</strong>, in my case it&#8217;s Larix Cam or whatever you want to put here. The <strong>Protocol </strong>is <strong>TS Over SRT</strong> and the port is <strong>50000</strong>. The <strong>Mode </strong>is <strong>Listener </strong>and the rest are the defaults. As I said earlier, if you want a better throughput, read the SRT deployment guide doc that I&#8217;ve sent earlier. It will tell you how to tweak these parameters. So, this tells the Media Gateway to listen on port UDP 50000 for any incoming broadcast.<br />
Now, click on the <strong>Destination </strong>button.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-05.png" alt="" width="1082" height="131" class="aligncenter size-full wp-image-6683" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-05.png 1082w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-300x36.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-1024x124.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-768x93.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-585x71.png 585w" sizes="(max-width: 1082px) 100vw, 1082px" /></a><br />
The <strong>Destination </strong>is where the broadcast will be distributed. So, you got the point now. A camera on your phone sends the video to our instance in AWS and this instance (Media Gateway) distributes the feed to numerous viewers. You can&#8217;t stream from your phone directly, because your phone&#8217;s bandwidth and horse power are minuscule, so you need a gateway.<br />
Here is how the <strong>Destination </strong>looks like.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-06.png" alt="" width="657" height="753" class="aligncenter size-full wp-image-6684" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-06.png 657w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-06-262x300.png 262w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-06-585x670.png 585w" sizes="(max-width: 657px) 100vw, 657px" /></a><br />
Name the destination however you like, make sure the <strong>Protocol </strong>is <strong>TS over SRT</strong> and the <strong>Port </strong>is 50001. The Media Gateway passes the signal from UDP 50000 (source) to UDP 50001 (destination). Can you use some other ports? Yes, you can as long as they are not the same and greater than 1024 and less than 65535. Change the <strong>Type </strong>to <strong>Listener </strong>and leave the rest of the parameters as-is. Again, read the SRT Deployment Guide. Click <strong>Add </strong>and once you go back, click <strong>Create </strong>to create the route.<br />
<strong>SUPER IMPORTANT</strong>: Make sure you edit the security group for this instance and open the ports for the source and destination. In my case, you have to add UDP ports 50000 and 50001 to the rules of the security group.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-07.png" alt="" width="1094" height="527" class="aligncenter size-full wp-image-6685" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-07.png 1094w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-300x145.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-1024x493.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-768x370.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-585x282.png 585w" sizes="(max-width: 1094px) 100vw, 1094px" /></a></p>
<h1>Larix Broadcaster app</h1>
<p>On your phone download this app from Google Play or App Store. Go to <strong>Settings </strong>(the gear icon), <strong>Connections </strong>and click on the <strong>(+)</strong> sign to add a connection.<br />
Enter a name for your connection, and for the URL enter the public IP of your instance and the port of the listener, so it looks like <strong>srt://public_IP:port</strong>. Make sure you specify <strong>srt://</strong> as prefix. The defaults are 640&#215;480 with audio, but you can change that in the settings for the app. Now, that you have a connection, make sure it&#8217;s active by selecting it and after that just hit the <strong>Record </strong>button. If something is not right, you&#8217;ll see it right away on your camera. It will tell you that the app can&#8217;t connect to the server. And if everything is OK after about 8-10 seconds you&#8217;ll see a green dot next to your source in the Media Gateway.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-09.png" alt="" width="1039" height="134" class="aligncenter size-full wp-image-6687" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-09.png 1039w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-300x39.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-1024x132.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-768x99.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-585x75.png 585w" sizes="(max-width: 1039px) 100vw, 1039px" /></a></p>
<h1>VLC PLayer</h1>
<p>There is really nothing much to say here. Go to <a href="https://www.videolan.org/vlc/index.html" rel="noopener noreferrer" target="_blank">this </a>website, download and install <strong>VLC </strong>and from the menu click on <strong>Media | Open Network Stream</strong>. Enter the IP address of the AWS instance and specify the destination port like <strong>srt://public_IP:port</strong>. Make sure you specify the destination port, not the source port and the protocol should be srt.</p>
<h1>Stream a video file (optional)</h1>
<p>In case you want your source to be a video file instead of a camera stream, reconfigure the source or add another route with new source and destination of which the source is RTMP. Configure the source so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-10.png" alt="" width="1096" height="819" class="aligncenter size-full wp-image-6690" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-10.png 1096w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-300x224.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-1024x765.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-768x574.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-585x437.png 585w" sizes="(max-width: 1096px) 100vw, 1096px" /></a><br />
From another server send the video stream to the Media Gateway using this command (you need ffmpeg installed).</p>
<pre class="brush: bash; title: ; notranslate">
ffmpeg -re -i video-file.mp4 -c copy -f flv rtmp://media_gateway_ip/live/stream
</pre>
<p>In VLC, use the <strong>srt://media_gateway_ip:port</strong> to watch the stream.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2020/05/general-how-to-stream-broadcast-from-your-phone/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>FreeBSD: icecast &#038; ices &#8211; stream your music on the Internet</title>
		<link>https://blog.andreev.it/2014/09/freebsd-10-icecast-ices/</link>
					<comments>https://blog.andreev.it/2014/09/freebsd-10-icecast-ices/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 28 Sep 2014 11:54:44 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[icecast]]></category>
		<category><![CDATA[ices]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[streaming]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=1522</guid>

					<description><![CDATA[In this post I&#8217;ll describe how to install and configure a streaming radio station&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post I&#8217;ll describe how to install and configure a streaming radio station with two separate streams. This means, you can have two or multiple radio stations running on the same port. For this, you&#8217;ll need a FreeBSD 10 server and some Ogg Vorbis music files. MP3 is not supported with ices2 client (licensing issues), but it&#8217;s easy to overcome that.</p>
<p>Before going any further, this is what you need to know.</p>
<ul>
<li><a href="http://icecast.org/" target="_blank" rel="noopener noreferrer">icecast</a> is the streaming server</li>
<li><a href="http://icecast.org/ices/" target="_blank" rel="noopener noreferrer">ices</a> is the client that supplies the music files to icecast</li>
<li>you are the listener, not a client</li>
</ul>
<h1>Install icecast</h1>
<p>icecast can be easily installed from the packages or the ports. There is no need for any configurations, so we&#8217;ll do the packages.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install icecast2
</pre>
<p>icecast comes up with a startup script, so we have to enable it on boot. Add the following line to <strong>/etc/rc.conf</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
icecast_enable=&quot;yes&quot;
</pre>
<p>icecast also comes up with a sample config script, so let&#8217;s modify it. The configuration parameters are described in the official <a href="http://icecast.org/docs/" target="_blank" rel="noopener noreferrer">document</a> and this post will highlight only the necessary changes that you have to make. </p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/
cp icecast.xml.sample icecast.xml
</pre>
<p>Change the location, the admin email, change the passwords for source-password, relay-password and admin-password under authentication. It&#8217;s a good practice to change the default admin user as well. In addition, change the log directory under logdir and uncomment the user and the group that will run icecast daemon. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2014/09/P046-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/09/P046-01.png" alt="" width="345" height="156" class="aligncenter size-full wp-image-7110" srcset="https://blog.andreev.it/wp-content/uploads/2014/09/P046-01.png 345w, https://blog.andreev.it/wp-content/uploads/2014/09/P046-01-300x136.png 300w" sizes="(max-width: 345px) 100vw, 345px" /></a><br />
This is how my <strong>icecast.xml</strong> looks like. </p>
<pre class="brush: bash; title: ; notranslate">
&lt;icecast&gt;
    &lt;!-- location and admin are two arbitrary strings that are e.g. visible
         on the server info page of the icecast web interface
         (server_version.xsl). --&gt;
    &lt;location&gt;NJ&lt;/location&gt;
    &lt;admin&gt;icemaster@iandreev.com&lt;/admin&gt;

    &lt;limits&gt;
        &lt;clients&gt;10&lt;/clients&gt;
        &lt;sources&gt;2&lt;/sources&gt;
        &lt;threadpool&gt;5&lt;/threadpool&gt;
        &lt;queue-size&gt;524288&lt;/queue-size&gt;
        &lt;client-timeout&gt;30&lt;/client-timeout&gt;
        &lt;header-timeout&gt;15&lt;/header-timeout&gt;
        &lt;source-timeout&gt;10&lt;/source-timeout&gt;
        &lt;!-- If enabled, this will provide a burst of data when a client 
             first connects, thereby significantly reducing the startup 
             time for listeners that do substantial buffering. However,
             it also significantly increases latency between the source
             client and listening client.  For low-latency setups, you
             might want to disable this. --&gt;
        &lt;burst-on-connect&gt;1&lt;/burst-on-connect&gt;
        &lt;!-- same as burst-on-connect, but this allows for being more
             specific on how much to burst. Most people won't need to
             change from the default 64k. Applies to all mountpoints  --&gt;
        &lt;burst-size&gt;65535&lt;/burst-size&gt;
    &lt;/limits&gt;

    &lt;authentication&gt;
        &lt;!-- Sources log in with username 'source' --&gt;
        &lt;source-password&gt;password1&lt;/source-password&gt;
        &lt;!-- Relays log in username 'relay' --&gt;
        &lt;relay-password&gt;password2&lt;/relay-password&gt;

        &lt;!-- Admin logs in with the username given below --&gt;
        &lt;admin-user&gt;username&lt;/admin-user&gt;
        &lt;admin-password&gt;password3&lt;/admin-password&gt;
    &lt;/authentication&gt;

    &lt;!-- set the mountpoint for a shoutcast source to use, the default if not
         specified is /stream but you can change it here if an alternative is
         wanted or an extension is required
    &lt;shoutcast-mount&gt;/live.nsv&lt;/shoutcast-mount&gt;
    --&gt;

    &lt;!-- Uncomment this if you want directory listings --&gt;
    &lt;!--
    &lt;directory&gt;
        &lt;yp-url-timeout&gt;15&lt;/yp-url-timeout&gt;
        &lt;yp-url&gt;http://dir.xiph.org/cgi-bin/yp-cgi&lt;/yp-url&gt;
    &lt;/directory&gt;
     --&gt;

    &lt;!-- This is the hostname other people will use to connect to your server.
    It affects mainly the urls generated by Icecast for playlists and yp
    listings. --&gt;
    &lt;hostname&gt;localhost&lt;/hostname&gt;

    &lt;!-- You may have multiple &lt;listener&gt; elements --&gt;
    &lt;listen-socket&gt;
        &lt;port&gt;8000&lt;/port&gt;
        &lt;!-- &lt;bind-address&gt;127.0.0.1&lt;/bind-address&gt; --&gt;
        &lt;!-- &lt;shoutcast-mount&gt;/stream&lt;/shoutcast-mount&gt; --&gt;
    &lt;/listen-socket&gt;
    &lt;!--
    &lt;listen-socket&gt;
        &lt;port&gt;8001&lt;/port&gt;
    &lt;/listen-socket&gt;
    --&gt;

    &lt;!--&lt;master-server&gt;127.0.0.1&lt;/master-server&gt;--&gt;
    &lt;!--&lt;master-server-port&gt;8001&lt;/master-server-port&gt;--&gt;
    &lt;!--&lt;master-update-interval&gt;120&lt;/master-update-interval&gt;--&gt;
    &lt;!--&lt;master-password&gt;hackme&lt;/master-password&gt;--&gt;

    &lt;!-- setting this makes all relays on-demand unless overridden, this is
         useful for master relays which do not have &lt;relay&gt; definitions here.
         The default is 0 --&gt;
    &lt;!--&lt;relays-on-demand&gt;1&lt;/relays-on-demand&gt;--&gt;

    &lt;!--
    &lt;relay&gt;
        &lt;server&gt;127.0.0.1&lt;/server&gt;
        &lt;port&gt;8001&lt;/port&gt;
        &lt;mount&gt;/example.ogg&lt;/mount&gt;
        &lt;local-mount&gt;/different.ogg&lt;/local-mount&gt;
        &lt;on-demand&gt;0&lt;/on-demand&gt;

        &lt;relay-shoutcast-metadata&gt;0&lt;/relay-shoutcast-metadata&gt;
    &lt;/relay&gt;
    --&gt;

    &lt;!-- Only define a &lt;mount&gt; section if you want to use advanced options,
         like alternative usernames or passwords
    &lt;mount&gt;
        &lt;mount-name&gt;/example-complex.ogg&lt;/mount-name&gt;

        &lt;username&gt;othersource&lt;/username&gt;
        &lt;password&gt;hackmemore&lt;/password&gt;

        &lt;max-listeners&gt;1&lt;/max-listeners&gt;
        &lt;dump-file&gt;/tmp/dump-example1.ogg&lt;/dump-file&gt;
        &lt;burst-size&gt;65536&lt;/burst-size&gt;
        &lt;fallback-mount&gt;/example2.ogg&lt;/fallback-mount&gt;
        &lt;fallback-override&gt;1&lt;/fallback-override&gt;
        &lt;fallback-when-full&gt;1&lt;/fallback-when-full&gt;
        &lt;intro&gt;/example_intro.ogg&lt;/intro&gt;
        &lt;hidden&gt;1&lt;/hidden&gt;
        &lt;no-yp&gt;1&lt;/no-yp&gt;
        &lt;authentication type=&quot;htpasswd&quot;&gt;
                &lt;option name=&quot;filename&quot; value=&quot;myauth&quot;/&gt;
                &lt;option name=&quot;allow_duplicate_users&quot; value=&quot;0&quot;/&gt;
        &lt;/authentication&gt;
        &lt;on-connect&gt;/home/icecast/bin/stream-start&lt;/on-connect&gt;
        &lt;on-disconnect&gt;/home/icecast/bin/stream-stop&lt;/on-disconnect&gt;
    &lt;/mount&gt;

    &lt;mount&gt;
        &lt;mount-name&gt;/auth_example.ogg&lt;/mount-name&gt;
        &lt;authentication type=&quot;url&quot;&gt;
            &lt;option name=&quot;mount_add&quot;       value=&quot;http://myauthserver.net/notify_mount.php&quot;/&gt;
            &lt;option name=&quot;mount_remove&quot;    value=&quot;http://myauthserver.net/notify_mount.php&quot;/&gt;
            &lt;option name=&quot;listener_add&quot;    value=&quot;http://myauthserver.net/notify_listener.php&quot;/&gt;
            &lt;option name=&quot;listener_remove&quot; value=&quot;http://myauthserver.net/notify_listener.php&quot;/&gt;
            &lt;option name=&quot;headers&quot;         value=&quot;x-pragma,x-token&quot;/&gt;
            &lt;option name=&quot;header_prefix&quot;   value=&quot;ClientHeader.&quot;/&gt;
        &lt;/authentication&gt;
    &lt;/mount&gt;

    --&gt;

    &lt;fileserve&gt;1&lt;/fileserve&gt;

    &lt;paths&gt;
		&lt;!-- basedir is only used if chroot is enabled --&gt;
        &lt;basedir&gt;/usr/local/share/icecast&lt;/basedir&gt;

        &lt;!-- Note that if &lt;chroot&gt; is turned on below, these paths must both
             be relative to the new root, not the original root --&gt;
        &lt;logdir&gt;/var/log/icecast&lt;/logdir&gt;
        &lt;webroot&gt;/usr/local/share/icecast/web&lt;/webroot&gt;
        &lt;adminroot&gt;/usr/local/share/icecast/admin&lt;/adminroot&gt;
        &lt;!-- &lt;pidfile&gt;/usr/local/share/icecast/icecast.pid&lt;/pidfile&gt; --&gt;

        &lt;!-- Aliases: treat requests for 'source' path as being for 'dest' path
             May be made specific to a port or bound address using the &quot;port&quot;
             and &quot;bind-address&quot; attributes.
          --&gt;
        &lt;!--
        &lt;alias source=&quot;/foo&quot; destination=&quot;/bar&quot;/&gt;
          --&gt;
        &lt;!-- Aliases: can also be used for simple redirections as well,
             this example will redirect all requests for http://server:port/ to
             the status page
          --&gt;
        &lt;alias source=&quot;/&quot; destination=&quot;/status.xsl&quot;/&gt;
    &lt;/paths&gt;

    &lt;logging&gt;
        &lt;accesslog&gt;access.log&lt;/accesslog&gt;
        &lt;errorlog&gt;error.log&lt;/errorlog&gt;
        &lt;!-- &lt;playlistlog&gt;playlist.log&lt;/playlistlog&gt; --&gt;
      	&lt;loglevel&gt;3&lt;/loglevel&gt; &lt;!-- 4 Debug, 3 Info, 2 Warn, 1 Error --&gt;
      	&lt;logsize&gt;10000&lt;/logsize&gt; &lt;!-- Max size of a logfile --&gt;
        &lt;!-- If logarchive is enabled (1), then when logsize is reached
             the logfile will be moved to &#x5B;error|access|playlist].log.DATESTAMP,
             otherwise it will be moved to &#x5B;error|access|playlist].log.old.
             Default is non-archive mode (i.e. overwrite)
        --&gt;
        &lt;!-- &lt;logarchive&gt;1&lt;/logarchive&gt; --&gt;
    &lt;/logging&gt;

    &lt;security&gt;
        &lt;chroot&gt;0&lt;/chroot&gt;
        &lt;changeowner&gt;
            &lt;user&gt;nobody&lt;/user&gt;
            &lt;group&gt;nogroup&lt;/group&gt;
        &lt;/changeowner&gt;
    &lt;/security&gt;
&lt;/icecast&gt;
</pre>
<p>Create the log directory and change the ownership.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /var/log/icecast
chown -R nobody:nogroup /var/log/icecast
</pre>
<p>Start the icecast and check the log file.</p>
<pre class="brush: bash; title: ; notranslate">
service icecast2 start
tail /var/log/icecast/error.log
</pre>
<p>If everything is OK you&#8217;ll see something like this.</p>
<pre class="brush: plain; title: ; notranslate">
&#x5B;2014-09-13  23:34:13] INFO main/main Icecast 2.4.0 server started
&#x5B;2014-09-13  23:34:13] INFO connection/get_ssl_certificate No SSL capability on any configured ports
&#x5B;2014-09-13  23:34:13] INFO yp/yp_update_thread YP update thread started
</pre>
<p>Go to <strong>http://yourserver.com:8000</strong> and you should see this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2014/09/P046-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/09/P046-02.png" alt="" width="916" height="248" class="aligncenter size-full wp-image-7111" srcset="https://blog.andreev.it/wp-content/uploads/2014/09/P046-02.png 916w, https://blog.andreev.it/wp-content/uploads/2014/09/P046-02-300x81.png 300w, https://blog.andreev.it/wp-content/uploads/2014/09/P046-02-768x208.png 768w, https://blog.andreev.it/wp-content/uploads/2014/09/P046-02-585x158.png 585w" sizes="(max-width: 916px) 100vw, 916px" /></a><br />
Then go to <strong>http://yourserver.com:8000/admin/stats.xml</strong> and you should see this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2014/09/P046-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2014/09/P046-03.png" alt="" width="765" height="494" class="aligncenter size-full wp-image-7112" srcset="https://blog.andreev.it/wp-content/uploads/2014/09/P046-03.png 765w, https://blog.andreev.it/wp-content/uploads/2014/09/P046-03-300x194.png 300w, https://blog.andreev.it/wp-content/uploads/2014/09/P046-03-585x378.png 585w" sizes="(max-width: 765px) 100vw, 765px" /></a></p>
<h1>Install ices</h1>
<p>We&#8217;ll install ices from the packages and create a separate user and group called <strong>radio</strong> that will run the ices client. Ices client doesn&#8217;t come up with a startup script, so we&#8217;ll create one for each stream. In case you reboot, the streaming server and the clients will start automatically. We&#8217;ll also create a log directory. </p>
<pre class="brush: bash; title: ; notranslate">
pkg install ices
pw groupadd radio &amp;&amp; pw useradd radio -g radio –m
mkdir /var/log/ices
chown –R radio:radio /var/log/ices
</pre>
<p>Switch to the <strong>radio</strong> user and create the folders for the configuration files and the two radio stations that you want to run. If you want more streams, just follow the pattern described bellow. In my case, I&#8217;ll have two radio stations, trance and liquid.</p>
<pre class="brush: bash; title: ; notranslate">
su - radio
mkdir conf liquid trance
cd ~radio/conf
cp /usr/local/share/ices/ices-playlist.xml liquid-playlist.xml
</pre>
<p>Let&#8217;s configure the first radio station and you&#8217;ll see how easy is to configure the the second one. </p>
<ul>
<li>Edit the configuration file for the first stream (<strong>liquid-playlist.xml</strong>) and change the following values: background, logpath, logfile and pidfile.</li>
<li>Under <strong>stream</strong> section, change the name, genre and description.</li>
<li>Under the <strong>input</strong> section, change the <strong>param name=&#8221;file&#8221;</strong> parameter. This value should point to a file that contains each Ogg file in a separate line.</li>
<li>Under the <strong>instance</strong> section, change the password and the mount. The password supplied here must match the same <strong>source-password</strong> that was used to configure icecast (see line 31 in my example of icecast config). The mount parameter is how you are going to access the stream (e.g. <strong>http://yourserver.com:8000/station_name.ogg</strong>). Always end it up with <strong>.ogg</strong>.</li>
<li>I also change the <strong>nominal-bitrate</strong> to 128000, which means, ices will encode the streams as 128kbps streams. </li>
</ul>
<p>Make sure you have enough bandwidth to support this. Use the following <a href="http://servers.internet-radio.com/tools/bandwidth/" target="_blank" rel="noopener noreferrer">link</a> to determine your needs. </p>
<p>Finally, here is my <strong>liquid-playlist.xml</strong> file. </p>
<pre class="brush: bash; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;ices&gt;
    &lt;!-- run in background --&gt;
    &lt;background&gt;1&lt;/background&gt;
    &lt;!-- where logs, etc go. --&gt;
    &lt;logpath&gt;/var/log/ices&lt;/logpath&gt;
    &lt;logfile&gt;liquid.log&lt;/logfile&gt;
    &lt;!-- 1=error,2=warn,3=info,4=debug --&gt;
    &lt;loglevel&gt;4&lt;/loglevel&gt;
    &lt;!-- set this to 1 to log to the console instead of to the file above --&gt;
    &lt;consolelog&gt;0&lt;/consolelog&gt;

    &lt;!-- optional filename to write process id to --&gt;
    &lt;pidfile&gt;/home/radio/liquid.pid&lt;/pidfile&gt;

    &lt;stream&gt;
        &lt;!-- metadata used for stream listing (not currently used) --&gt;
        &lt;metadata&gt;
            &lt;name&gt;Liquid radio&lt;/name&gt;
            &lt;genre&gt;Liquid D'n'B genre&lt;/genre&gt;
            &lt;description&gt;Commercial Free Liquid D'n'B radio stream&lt;/description&gt;
        &lt;/metadata&gt;

        &lt;!-- input module

            The module used here is the playlist module - it has 
            'submodules' for different types of playlist. There are
            two currently implemented, 'basic', which is a simple
            file-based playlist, and 'script' which invokes a command
            to returns a filename to start playing. --&gt;

        &lt;input&gt;
            &lt;module&gt;playlist&lt;/module&gt;
            &lt;param name=&quot;type&quot;&gt;basic&lt;/param&gt;
            &lt;param name=&quot;file&quot;&gt;/home/radio/conf/liquid-playlist.txt&lt;/param&gt;
            &lt;!-- random play --&gt;
            &lt;param name=&quot;random&quot;&gt;0&lt;/param&gt;
            &lt;!-- if the playlist get updated that start at the beginning --&gt;
            &lt;param name=&quot;restart-after-reread&quot;&gt;0&lt;/param&gt;
            &lt;!-- if set to 1 , plays once through, then exits. --&gt;
            &lt;param name=&quot;once&quot;&gt;0&lt;/param&gt;
        &lt;/input&gt;

		&lt;!-- Stream instance
            You may have one or more instances here. This allows you to 
            send the same input data to one or more servers (or to different
            mountpoints on the same server). Each of them can have different
            parameters. This is primarily useful for a) relaying to multiple
            independent servers, and b) encoding/reencoding to multiple
            bitrates.
            If one instance fails (for example, the associated server goes
            down, etc), the others will continue to function correctly.
            This example defines two instances as two mountpoints on the
            same server.  --&gt;
        &lt;instance&gt;
            &lt;!-- Server details:
                You define hostname and port for the server here, along with
                the source password and mountpoint.  --&gt;
            &lt;hostname&gt;localhost&lt;/hostname&gt;
            &lt;port&gt;8000&lt;/port&gt;
            &lt;password&gt;password1&lt;/password&gt;
            &lt;mount&gt;/liquid.ogg&lt;/mount&gt;

            &lt;!-- Reconnect parameters:
                When something goes wrong (e.g. the server crashes, or the
                network drops) and ices disconnects from the server, these
                control how often it tries to reconnect, and how many times
                it tries to reconnect. Delay is in seconds.
                If you set reconnectattempts to -1, it will continue 
                indefinately. Suggest setting reconnectdelay to a large value
                if you do this.
            --&gt;
            &lt;reconnectdelay&gt;2&lt;/reconnectdelay&gt;
            &lt;reconnectattempts&gt;5&lt;/reconnectattempts&gt; 

            &lt;!-- maxqueuelength:
                This describes how long the internal data queues may be. This
                basically lets you control how much data gets buffered before
                ices decides it can't send to the server fast enough, and 
                either shuts down or flushes the queue (dropping the data)
                and continues. 
                For advanced users only.
            --&gt;
            &lt;maxqueuelength&gt;80&lt;/maxqueuelength&gt;

            &lt;!-- Live encoding/reencoding:
                Currrently, the parameters given here for encoding MUST
                match the input data for channels and sample rate. That 
                restriction will be relaxed in the future.
                Remove this section if you don't want your files getting reencoded.
            --&gt;
            &lt;encode&gt;  
                &lt;nominal-bitrate&gt;128000&lt;/nominal-bitrate&gt; &lt;!-- bps. e.g. 64000 for 64 kbps --&gt;
                &lt;samplerate&gt;44100&lt;/samplerate&gt;
                &lt;channels&gt;2&lt;/channels&gt;
            &lt;/encode&gt;
        &lt;/instance&gt;

	&lt;/stream&gt;
&lt;/ices&gt;
</pre>
<p>At this point, we need to put some Ogg files that we want to stream. In my case, I&#8217;ve put them under /<strong>home/radio/liquid</strong> for the first stream. Now, go to:</p>
<pre class="brush: bash; title: ; notranslate">
cd ~radio/conf
ls -d /home/radio/liquid/*.ogg &gt; liquid-playlist.txt
cat liquid-playlist.txt
</pre>
<p>This will generate the playlist for you from all Ogg files. If you have your files separated in sub directories, then do:</p>
<pre class="brush: bash; title: ; notranslate">
cd ~radio/genre
find /home/radio/genre -name &quot;*.ogg&quot; -print &gt; /home/radio/conf/genre-playlist.txt
</pre>
<p>At this point, start the station with <strong>ices liquid-playlist.xml</strong>. If everything is OK, you shouldn&#8217;t see anything. Ices will start in the background. Do a simple check:</p>
<pre class="brush: bash; title: ; notranslate">
ps -waux | grep ices
tail /var/log/ices/liquid.log
</pre>
<p>Check your radio with <strong>http://yourserver.com:8000/liquid.ogg</strong>. Now that you have the first radio ready, it&#8217;s very easy to configure the 2nd one. First, let&#8217;s create the configuration file as a copy from the first station.</p>
<pre class="brush: bash; title: ; notranslate">
cd ~radio/conf
cp liquid-playlist.xml trance-playlist.xml
</pre>
<p>I use <strong>vi</strong> to replace everything in <strong>trance-playlist.xml</strong> that says liquid as trance. Use <strong>:%s/liquid/trance/g</strong>.</p>
<p>Put some Ogg file for the 2nd station under <strong>~radio/trance</strong> and create the playlist text file. </p>
<pre class="brush: bash; title: ; notranslate">
cd ~radio/conf
ls -d /home/radio/trance/*.ogg &gt; trance-playlist.txt
cat trance-playlist.txt
</pre>
<p>Start the station with <strong>ices trance-playlist.xml</strong> and test it with <strong>http://yourserver.com:8000/trance.ogg</strong>.</p>
<h1>Configure ices startup</h1>
<p>Once you make sure that everything works fine, let&#8217;s create the ices startup files in case the server reboots. </p>
<p>Log as root and do:</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/rc.d
</pre>
<p>Create the first startup script called <strong>ices_liquid</strong> and add everything from here.</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
#
# PROVIDE: ices_liquid
# REQUIRE: DAEMON icecast2
# BEFORE:  LOGIN
# KEYWORD: shutdown

. /etc/rc.subr

name=&quot;ices_liquid&quot;
rcvar=ices_liquid_enable

command=&quot;/usr/local/bin/ices&quot;
extra_commands=&quot;reload&quot;
pidfile=&quot;/home/radio/liquid.pid&quot;
sig_reload=&quot;USR1&quot;

load_rc_config &quot;$name&quot;
: ${ices_liquid_enable=&quot;NO&quot;}
: ${ices_liquid_config=&quot;/home/radio/conf/liquid-playlist.xml&quot;}
: ${ices_liquid_flags=&quot;${ices_liquid_config}&quot;}
: ${ices_liquid_user=&quot;radio&quot;}
required_files=&quot;${ices_liquid_config}&quot;

run_rc_command &quot;$1&quot;

</pre>
<p>Save it and do <strong>chmod 555 ices_liquid</strong> to make sure it&#8217;s executable on start. Add <strong>ices_liquid_enable=&#8221;YES&#8221;</strong> in <strong>/etc/rc.conf</strong>. Follow the same pattern for the second startup script. Copy ices_liquid as ices_trance and replace every occurrence of liquid as trance. Then add <strong>ices_trance_enable=&#8221;YES&#8221;</strong> in <strong>/etc/rc.conf</strong>. Now you can control the streams with the standard FreeBSD daemon command <strong>service</strong>. E.g.</p>
<pre class="brush: bash; title: ; notranslate">
service ices_liquid start
service ices_liquid stop
service ices_liquid status
</pre>
<p>OK. At this point you have a streaming station(s) but they all run on port 8000. As we stated above, you can access a station by accessing this URL: <strong>http://genre.domain.com:8000/genre.ogg</strong>, speaking in general terms. Read further to see how can you bypass this restriction in order to access your radio behind a firewall.</p>
<h1>Firewall</h1>
<p>icecast runs on port 8000 and in many corporate environments only ports 80 and 443 are allowed inbound through various proxies. I tried to run icecast on port 80, but icecast refused to run. Mind that you can&#8217;t run icecast using a non-root account on port 80. Actually, you can. apache runs on port 80 as www user, but it&#8217;s parent process runs as root and then forks the processes. But most importantly, if you somehow make icecast to run as root, you can&#8217;t run apache on that port. The easiest way is to use <strong>mod_proxy</strong>. This module will do the heavy lifting for you. It will redirect port 8000 to port 80. This is how we are going to accomplish that using two virtual hosts in Apache.<br />
First, create two DNS aliases, e.g. <strong>genre.domain.com</strong> and <strong>genrefw.domain.com</strong>. They should point to the same IP of your icecast server. In Apache, make sure you have <strong>mod_proxy</strong> and <strong>mod_proxy_html</strong> modules built in and loaded in <strong>httpd.conf</strong>. See my other <a href="https://blog.andreev.it/?p=1309" target="_blank" rel="noopener noreferrer">post</a> on how to run virtual hosts under Apache. </p>
<pre class="brush: bash; title: ; notranslate">
LoadModule proxy_module libexec/apache24/mod_proxy.so
LoadModule proxy_http_module libexec/apache24/mod_proxy_http.so
LoadModule cgi_module libexec/apache24/mod_cgi.so
</pre>
<p>or if you have the prefork/worker config file, you might also see this.</p>
<pre class="brush: plain; title: ; notranslate">
&lt;IfModule mpm_prefork_module&gt;
        LoadModule cgi_module libexec/apache24/mod_cgi.so
&lt;/IfModule&gt;
</pre>
<p>The virtual hosts directives in <strong>httpd-vhosts.conf</strong> should look like this.</p>
<pre class="brush: bash; title: ; notranslate">
&lt;VirtualHost *:80&gt;
    ServerAdmin admin@domain.com
    DocumentRoot &quot;/usr/local/www/genre.domain.com&quot;
    ServerName genre.domain.com
    ErrorLog &quot;/var/log/genre.domain.com-error_log&quot;
    CustomLog &quot;/var/log/genre.domain.com-access_log&quot; common
    &lt;Directory &quot;/usr/local/www/genre.domain.com&quot;&gt;
        Options All
        AllowOverride All
        Require all granted
   &lt;/Directory&gt;
   ScriptAlias /cgi-bin/ &quot;/usr/local/www/genre.domain.com/cgi-bin/&quot;
   &lt;Directory &quot;/usr/local/www/genre.domain.com/cgi-bin&quot;&gt;
        Options +ExecCGI
        Order allow,deny
        Allow from all
        AddHandler cgi-script .cgi
   &lt;/Directory&gt;
&lt;/VirtualHost&gt;
&lt;VirtualHost *:80&gt;
    ServerAdmin admin@domain.com
    DocumentRoot &quot;/usr/local/www/genrefw.domain.com&quot;
    ServerName genrefw.domain.com
    ErrorLog &quot;/var/log/genrefw.domain.com-error_log&quot;
    CustomLog &quot;/var/log/genrefw.domain.com-access_log&quot; common
    ProxyRequests Off
    ProxyPass / http://genre.domain.com:8000/genre.ogg
    ProxyPassReverse / http://genre.domain.com:8000/genre.ogg
    &lt;Directory &quot;/usr/local/www/genrefw.domain.com&quot;&gt;
        Options All
        AllowOverride All
        Require all granted
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>
<p>Now, you have to create two virtual web sites, <strong>genre.domain.com</strong> and <strong>genrefw.domain.com</strong>. The <strong>genrefw.domain.com</strong> site will be an empty site. Read further and see how I built two web sites. You can make it much simpler or even more complex. I also enabled cgi-bin in order to run some scripts. The step below is optional. If you just want to bypass the firewall, create the two virtual hosts as described above and for regular users use <strong>http://genre.domain.com:8000/genre.ogg</strong> and for the users behind a firewall use <strong>http://genrefw.domain.com/genre.ogg</strong>.</p>
<h1>Optional</h1>
<p>I&#8217;ll create a web page that embeds the player and shows some info. There is a HTML5 menu and one of the options will tell you what track is currently playing. That&#8217;s why we needed cgi-bin. Here are my HTML and CSS files. Make sure you have 10 background images in the same directory, from background0.jpg to background9.jpg. They will rotate every 90 seconds. It looks cool! :) First, let&#8217;s create the cgi-bin folder under the virtual host destination.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/www/genre.domain.com
mkdir cgi-bin
</pre>
<p>Then create a file called <strong>info.cgi</strong> that contains the following:</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
echo &quot;Content-type: text/html&quot;
echo &quot;&quot;

echo '&lt;html&gt;'
echo '&lt;head&gt;'
echo '&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;'
echo '&lt;title&gt;Currently Playing &lt;/title&gt;'
echo '&lt;/head&gt;'
echo '&lt;body&gt;'
grep &quot;INFO playlist&quot; /var/log/ices/genre.log | tail -n 1 | sed 's/ INFO playlist-builtin\/playlist_read//' | sed 's/&quot;//g' | sed 's/\/home\/radio\/genre\///'
echo '&lt;/body&gt;'
echo '&lt;/html&gt;'
exit 0
</pre>
<p>Then change permissions.</p>
<pre class="brush: plain; title: ; notranslate">
chmod 755 info.cgi
</pre>
<p>What this script does? It creates a simple HTML file from the output of the grep command. It just looks for the last appearance of the current playing track in the ices log. </p>
<p>Here is the HTML file.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Genre Radio&lt;/title&gt;
            &lt;link rel=&quot;stylesheet&quot; href=&quot;styles.css&quot; /&gt;
	    &lt;script&gt;
                function run(interval, frames) {
                     var int = 0;
    		     function func() {
        		document.body.id = &quot;bg&quot;+int;
        		int++;
        		if(int == frames) { int = 0; }
    		     }
   		     var swap = window.setInterval(func, interval);
	        }
		run(90000, 10); //milliseconds, frames
	&lt;/script&gt;
    &lt;/head&gt;
&lt;body id=&quot;bg&quot;&gt;
&lt;!-- http://red-team-design.com/css3-dropdown-menu/ --&gt;
&lt;BR&gt;&amp;nbsp;&lt;BR&gt; 
&lt;ul id=&quot;menu&quot;&gt;
    &lt;li&gt;&lt;a href=&quot;/&quot; onclick=&quot;window.open('http://genre.domain.com/cgi-bin/info.cgi', 'newwindow', 'width=300, height=100'); return false;&quot;&gt;INFO&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;
        &lt;a href=&quot;#&quot;&gt;Radio&lt;/a&gt;
        &lt;ul&gt;
            &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Classical&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;http://genre2.domain.com/&quot; target=&quot;_blank&quot;&gt;Other Genre&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.andreev.it/&quot; target=&quot;_blank&quot;&gt;About&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/klimenta/&quot; target=&quot;_blank&quot;&gt;Contact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
    &lt;footer&gt;
        &lt;audio controls&gt;
             &lt;source src=&quot;http://genre.domain.com:8000/genre.ogg&quot; type=&quot;audio/ogg&quot;&gt;
             Your browser does not support the audio element.
        &lt;/audio&gt;
&lt;a class=&quot;tzine1&quot; href=&quot;/&quot; onclick=&quot;window.open('http://genrefw.iandreev.com', 'newwindow', 'width=300, height=100'); return false;&quot;&gt;No sound? Click &lt;i&gt;&lt;b&gt;here!&lt;/b&gt;&lt;/i&gt;&lt;/a&gt;
&lt;a class=&quot;tzine&quot; href=&quot;https://blog.andreev.it/&quot;&gt;Commercial Free Genre Radio: &lt;i&gt;Kliment Andreev&lt;b&gt; 2015&lt;/b&gt;&lt;/i&gt; (c)&lt;/a&gt;
    &lt;/footer&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>And the CSS file.</p>
<pre class="brush: css; title: ; notranslate">
*{
    margin: 0;
    padding: 0;
}

body#bg0 {
  background: url('background0.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg1 {
  background: url('background1.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg2 {
  background: url('background2.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg3 {
  background: url('background.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg4 {
  background: url('background4.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg5 {
  background: url('background5.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg6 {
  background: url('background6.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg7 {
  background: url('background7.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg8 {
  background: url('background8.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}
body#bg9 {
  background: url('background9.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;
}

a, a:visited {
        outline:none;
        color:#1c4f64;
}

a:hover{
        text-decoration:none;
}

section, footer, header{
        display: block;
}


footer{
        background-color: #111111;
        bottom: 0;
        box-shadow: 0 -1px 2px rgba(0,0,0,0.4);
        height: 45px;
        left: 0;
        position: fixed;
        width: 100%;
        z-index: 100000;
}

footer h2{
        color: #EEEEEE;
        font-size: 14px;
        font-weight: normal;
        left: 50%;
        margin-left: -400px;
        padding: 13px 0 0;
        position: absolute;
        width: 540px;
}
footer h2 i{
        font-style:normal;
        color:#888;
}

footer a.tzine,a.tzine:visited{
        color: #999999;
        font-size: 12px;
        left: 50%;
        margin: 16px 0 0 110px;
        position: absolute;
        text-decoration: none;
        top: 0;
}

footer a.tzine1,a.tzine1:visited{
        color: #999999;
        font-size: 12px;
        left: -5%;
        margin: 16px 0 0 110px;
        position: absolute;
        text-decoration: none;
        top: 0;
}

footer a i{
        color:#ccc;
        font-style: normal;
}

footer a i b{
        color:#c92020;
        font-weight: normal;
}


body{
        /* Workaround for some mobile browsers */
  background: url('background9.jpg') no-repeat 50% 50% fixed;
  background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  -webkit-background-size: cover;

        font:14px/1.3 'Segoe UI',Arial, sans-serif;
}

/* Main */
/* Original width e 100% a ne 30%&quot;*/
#menu {
    width: 30%;
    margin: 0;
    padding: 10px 0 0 0;
    list-style: none;  
    background-color: #111;
    background-image: linear-gradient(#444, #111);
    border-radius: 50px;
    box-shadow: 0 2px 1px #9c9c9c;
}

#menu li {
    float: left;
    padding: 0 0 10px 0;
    position: relative;
}

#menu a {
    float: left;
    height: 25px;
    padding: 0 25px;
    color: #999;
    text-transform: uppercase;
    font: bold 12px/25px Arial, Helvetica;
    text-decoration: none;
    text-shadow: 0 1px 0 #000;
}

#menu li:hover &gt; a {
    color: #fafafa;
}

*html #menu li a:hover { /* IE6 */
    color: #fafafa;
}

#menu li:hover &gt; ul {
    display: block;
}

/* Sub-menu */
#menu ul {
    list-style: none;
    margin: 0;
    padding: 0;    
    display: none;
    position: absolute;
    top: 35px;
    left: 0;
    z-index: 99999;    
    background-color: #444;   
    background-image: linear-gradient(#444, #111);    
    -moz-border-radius: 5px;
    border-radius: 5px;
}

#menu ul li {
    float: none;
    margin: 0;
    padding: 0;
    display: block;  
    box-shadow: 0 1px 0 #111111, 
                0 2px 0 #777777;
}

#menu ul li:last-child { 
    box-shadow: none;    
}

#menu ul a {    
    padding: 10px;
    height: auto;
    line-height: 1;
    display: block;
    white-space: nowrap;
    float: none;
    text-transform: none;
}

*html #menu ul a { /* IE6 */   
    height: 10px;
    width: 150px;
}

*:first-child+html #menu ul a { /* IE7 */    
    height: 10px;
    width: 150px;
}

#menu ul a:hover {
    background-color: #0186ba;
    background-image: linear-gradient(#04acec, #0186ba);
}

#menu ul li:first-child a {
    border-radius: 5px 5px 0 0;
}

#menu ul li:first-child a:after {
    content: '';
    position: absolute;
    left: 30px;
    top: -8px;
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-bottom: 8px solid #444;
}

#menu ul li:first-child a:hover:after {
    border-bottom-color: #04acec; 
}

#menu ul li:last-child a {
    border-radius: 0 0 5px 5px;
}

/* Clear floated elements */
#menu:after {
    visibility: hidden;
    display: block;
    font-size: 0;
    content: &quot; &quot;;
    clear: both;
    height: 0;
}

* html #menu             { zoom: 1; } /* IE6 */
*:first-child+html #menu { zoom: 1; } /* IE7 */

</pre>
<h1>Convert mp3 to ogg</h1>
<p>You can use the <strong>sox</strong> utility that comes in the ports.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install sox
</pre>
<p>Check the man page for detailed syntax, but I use simple conversion.</p>
<pre class="brush: bash; title: ; notranslate">
sox filename.mp3 filename.ogg
</pre>
<p>You can check the properties of any audio file with:</p>
<pre class="brush: bash; title: ; notranslate">
soxi filename
</pre>
<p>For batch conversion, create this script called <strong>mp32ogg.sh</strong> and execute it against all files in the folder. It will convert all mp3 files to ogg. Add sox parameters if needed.</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
for i in *.mp3; do
        sox ./&quot;$i&quot; ./&quot;${i%.mp3}.ogg&quot;
done
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2014/09/freebsd-10-icecast-ices/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		<enclosure url="http://genrefw.domain.com/genre.ogg" length="767" type="audio/ogg" />

			</item>
	</channel>
</rss>
