Icecast Interface¶
This module implements the interface to Icecast.
The stream uses the musicdb.lib.stream.libshout2
module as wrapper
to libshout
from the Icecast project.
Introduction to Icecast¶
A setup using Icecast consist of three components. Using Icecast’s terms, the are the following:
- Source Client:
This the software that provides the music. In this setup, it is MusicDB. It is called client, because it connects to Icecast that can manage multiple source clients.
- Icecast Server:
This is Icecast itself. It servers the audio stream to the world.
- Listener:
The listener is the receiver of the stream. For example VLC.
Icecast can handle multiple sources. Each source is used for the input of a Mountpoint. All Listeners that want to access the audio stream receives the data from this Mountpoint’s output.
For more details see the Icecast Documentation.
Icecast Configuration¶
The Icecast configuration defines the Source Client and how the data from the Source Clients gets served to the listeners.
In this section, I only point out the more important settings of the whole Icecast configuration. There is a good example configuration provided by MusicDB. The following list addresses the settings in the XML file for the Icecast configuration.
- icecast/authentication/source-password:
This is the password MusicDB needs to know to connect to Icecast. So this password must be the same as in MusicDB Configuration
[Icecast]->password
.
There are two ports needed for the MusicDB/Icecast setup. One port to connect MusicDB to Icecast, and one to provide the stream to Listeners. The MusicDB connection (Port 8001) is bound to localhost and not encrypted. The other port (8000) can be open to the world because it will be encrypted and protected against unwanted access.
The ports will be configured in the icecast
section of the configuration file by adding listen-socket
sections:
<!-- Extern --> <listen-socket> <port>8000</port> <ssl>1</ssl> </listen-socket> <!-- Intern --> <listen-socket> <port>8001</port> <ssl>0</ssl> <shoutcast-mount>/stream</shoutcast-mount> </listen-socket>
- icecast/listen-socket/shoutcast-mount:
This setting defines the Mountpoint name (starting with “/”). It must be the same like the one set in MusicDB’s configuration:
[Icecast]->mountname
Further more it must be equal to the name defined in the detailed mount specification:icecast/mount/mount-name
.
Icecast Class¶
- class musicdb.lib.stream.icecast.IcecastInterface(port, user, password, mountname)[source]¶
This Icecast interface manages the connection to the Icecast server.
The following values for setting up the connection via libshout are hard coded. They can easily be changed in the Icecast configuration in the
icecast/mount
section.Parameter
Value
Comment
protocol
SHOUT_PROTOCOL_HTTP
The native and recommended format for Icecast 2
format
SHOUT_FORMAT_MP3
Obvious. MusicDB streams mp3 files
public
0
For security and privacy reasons
host
"localhost"
For security reasons MusicDB and Icecast must run on the same computer
name
"MusicDB Stream"
dumpfile
None
Storing the stream does not make sense for non-moderated streams
url
None
There is no website for the stream, because it is a private stream
genre
None
Not relevant for private streams
description
None
Not relevant for private streams
agent
None
Not relevant
audio_info
None
Not relevant
The Icecast Interface class can stream any data to the Icecast Server via
StreamChunk()
. In general this should be not necessary! Instead only use theStreamFile()
method that streams a mp3 file addressed by its path. Advantage of theStreamFile()
is, beside a clean frame wise transfer of the data to the server, that the stream can be muted viaMute()
.- Parameters
port (int) – port number for the Source Client connection
user (str) – Name of the source user
password (str) – The password of the source user
mountname (str) – Name of the mountpoint to use.
Example
# Create IcecastInterface object icecast = IcecastInterface(666, "source", "hackme", "/stream") # Connect to the Icecast server icecast.Connect() # Stream one file for size, offset in icecast.StreamFile("/tmp/test.mp3"): print("%i of %i bytes sent"%(offset, size)) # Disconnect from the Icecast server icecast.Disconnect()
- Connect()[source]¶
Tries to connect to Icecast.
If already connected, only
True
gets returned with out opening again.- Returns
True
on success, otherwiseFalse
- Disconnect()[source]¶
Tries to close the Icecast connection.
If already disconnected, only
True
gets returned with out disconnecting again.- Returns
True
on success, otherwiseFalse
- Mute(state=True)[source]¶
This method sets the Icecast Interface into a mute state (when
state == True
). Then, the methodStreamFile()
streams silence instead of the file content. After leaving the mute state, the file streaming continues at the position it got muted (=paused)- Parameters
state (bool) – Mute stream when
True
, otherwise continue streaming audio- Returns
Nothing
- StreamChunk(chunk)[source]¶
This method send a chunk of a file to the Icecast server. The method synchronizes with Icecast before sending the data. This is a blocking process!
When sending a chunk of data to Icecast fails, the method disconnects from the Server.
- Parameters
chunk (bytes) – A chunk of a file to stream to Icecast
- Returns
True
on success,False
otherwise- Raises
TypeError – When
chunk
is not of type bytes
Example
with open(path) as mp3: while True: chunk = mp3.read(4096) if not chunk: print("File sent.") break retval = icecast.StreamChunk(chunk) if retval == False: print("ERROR") break
- StreamFile(path)[source]¶
This is a generator that sends a mp3 file to the Icecast server. The mp3 file gets split into its frames, and sent frame wise.
After sending one chunk, the generator returns a dictionary with exact the keys and values that gets returned by
musicdb.lib.stream.mp3stream.MP3Stream.Frames()
andmusicdb.lib.stream.mp3stream.MP3Stream.AnalyzeHeader()
This frame dictionary gets extended by one further key:
muted
. When this value isTrue
, then a silent frame got sent. In this case, all information in the dictionary relate to the next frame from the mp3 file that will be send when the stream continues. WhenFalse
then the information are related to the actual sent frame.Streaming of the file using this method allows to pause the audio stream by calling the
Mute()
method. Then instead of the frames from the file, a hard coded frame of pure silence gets streamed as long as the mute-state persists. Instead of one silent frame, 10 frames will be streamed at once. This is about 261ms of silence.The control flow is visualized in the following image:
The silent frame is optimized to be injected in the mp3-files generated by MusicDB for the MP3 Cache. The mp3 file was generated as shown in the script example below. Then the first frame was captured via the
musicdb.lib.stream.mp3stream.MP3Stream.Frames()
method.ffmpeg -filter_complex aevalsrc=0 -acodec libmp3lame -ab 320k -t 1 monosilence.mp3 ffmpeg -i monosilence.mp3 -ab 320k -ac 2 stereosilence.mp3
- Parameters
path (str) – Absolute path to the mp3 file to stream. The encoding must be the same for all files!
- Returns
Returns a generator that returns the currently streamed frame.
Example
for frameinfo in icecast.StreamFile(path): if frameinfo["muted"] == True: print("Stream is muted.") continue print("%i. frame of %i frames sent. Length: %s ms"%( frameinfo["count"], frameinfo["total"], frameinfo["header"]["frametime"] ))