README

DudelDu

DudelDu is a simple audio/video streaming server using the SHOUTcast protocol.

Code coverage Go Report Card Go Doc

Features

  • Supports various streaming clients: VLC, ServeStream, ... and most Icecast clients.
  • Supports sending of meta data (sending artist and title to the streaming client).
  • Playlists are simple JSON files and data files are normal media (e.g. .mp3, .nsv) files on disk.
  • Can be used as a stand-alone server or embedded in other Go projects.
  • Supports HTTP basic user authentication.

Getting Started (standalone application)

You can download a pre-compiled package for Windows (win64) or Linux (amd64) here.

You can also pull the latest docker image of DudelDu from Dockerhub:

docker pull krotik/dudeldu

Create an empty directory, change into it and run the following to start DudelDu:

docker run --rm --user $(id -u):$(id -g) -v $PWD:/data -p 9091:9091 krotik/dudeldu -host 0.0.0.0 <playlist>

The container will have access to the current local directory and all subfolders.

Demo

DudelDu comes with a demo playlist. After extracting DudelDu switch to the directory examples/demo. Run ./run_demo.sh (Linux) or run_demo.bat (Windows) to start the server.

Open a browser and view the demo.html in the examples/demo directory. To access the demo streams you are prompted for a username and password. The credentials are:

username: web
password: web

You can also point your favourite audio streaming client (e.g. VLC) to the streaming URL:

http://localhost:9091/bach/cello_suite1

The demo includes also a small video in the Nullsoft Streaming Video format (NSV). To see it point a video streaming client (e.g. VLC) to:

http://localhost:9091/trailer/big_buck_bunny

Note: By default you can only reach the streams via localhost. Use the -host parameter with a host name or IP address to expose it to external network peers.

Command line options

The main DudelDu executable has the following command line options:

DudelDu x.x.x
Usage of ./dudeldu [options] <playlist>
  -?	Show this help message
  -auth string
    	Authentication as <user>:<pass>
  -debug
    	Enable extra debugging output
  -fqs int
    	Frame queue size (default 10000)
  -host string
    	Server hostname to listen on (default "127.0.0.1")
  -loop
    	Loop playlists
  -port string
    	Server port to listen on (default "9091")
  -pp string
    	Prefix all paths with a string
  -shuffle
    	Shuffle playlists
  -tps int
    	Thread pool size (default 10)

Authentication can also be defined via the environment variable: DUDELDU_AUTH="<user>:<pass>"

Building DudelDu

To build DudelDu from source you need to have Go installed (go >= 1.12):

Create a directory, change into it and run:

git clone https://devt.de/krotik/dudeldu/ .

You can build DudelDu's executable with:

go build ./server/dudeldu.go

Building DudelDu as Docker image

DudelDu can be build as a secure and compact Docker image.

  • Create a directory, change into it and run:
git clone https://devt.de/krotik/dudeldu/ .
  • You can now build the Docker image with:
docker build --tag krotik/dudeldu .

License

DudelDu source code is available under the MIT License.

Documentation

Overview

Package dudeldu is a simple audio streaming server using the SHOUTcast protocol.

Server

Server is the main server object which runs a shoutcast server instance.

Using a WaitGroup a client can wait for the start and shutdown of the server. Incoming new connections are served with a ConnectionHandler method. The default implementation for this is the HandleRequest method of the DefaultRequestHandler object.

DefaultRequestHandler

DefaultRequestHandler is the default request handler implementation for the DudelDu server. DefaultRequestHandler has a customizable ServeRequest function. ServeRequest is called once a request was successfully decoded.

The default implementation supports sending meta data while streaming audio. The metadata implementation is according to:

http://www.smackfu.com/stuff/programming/shoutcast.html

Playlists

Playlists provide the data which is send to the client. A simple implementation will just read .mp3 files and send them in chunks (via the Frame() method) to the client.

A request handler uses a PlaylistFactory to produce a Playlist for each new connection.

Index

Constants

View Source
const FrameSize = 3000

FrameSize is the suggested size of a frame which should be send to the client at a time.

The absolute theoretical maximum frame size for a MPEG audio is 2881 bytes:

MPEG 2.5 Layer II, 8000 Hz @ 160 kbps, with a padding slot. Theoretical frame sizes for Layer III range from 24 to 1441 bytes there is a "soft" limit imposed by the standard of 960 bytes.

see: http://www.mars.org/pipermail/mad-dev/2002-January/000425.html

View Source
const MaxRequestSize = 1024

MaxRequestSize is the maximum size for a request

View Source
const ProductVersion = "1.3.1"

ProductVersion is the current version of DudelDu

Variables

View Source
var ErrPlaylistEnd = errors.New("End of playlist")

ErrPlaylistEnd is a special error code which signals that the end of the playlist has been reached

View Source
var MaxMetaDataSize = 4080

MaxMetaDataSize is the maximum size for meta data (everything over is truncated)

Must be a multiple of 16 which fits into one byte. Maximum: 16 * 255 = 4080

View Source
var MetaDataInterval uint64 = 65536

MetaDataInterval is the data interval in which meta data is send

Functions

This section is empty.

Types

type ConnectionHandler

type ConnectionHandler func(net.Conn, net.Error)

ConnectionHandler is a function to handle new connections

type DebugLogger

type DebugLogger interface {

	/*
		IsDebugOutputEnabled returns true if debug output is enabled.
	*/
	IsDebugOutputEnabled() bool

	/*
	   PrintDebug will print debug output if `DebugOutput` is enabled.
	*/
	PrintDebug(v ...interface{})
}

DebugLogger is the debug logging interface of the Server

type DefaultRequestHandler

type DefaultRequestHandler struct {
	PlaylistFactory PlaylistFactory // Factory for playlists
	ServeRequest    func(c net.Conn, path string,
		metaDataSupport bool, offset int, auth string) // Function to serve requests

	LoopTimes int // Number of loops -1 loops forever
	// contains filtered or unexported fields
}

DefaultRequestHandler data structure

func NewDefaultRequestHandler

func NewDefaultRequestHandler(pf PlaylistFactory, loop bool,
	shuffle bool, auth string) *DefaultRequestHandler

NewDefaultRequestHandler creates a new default request handler object.

func (*DefaultRequestHandler) HandleRequest

func (drh *DefaultRequestHandler) HandleRequest(c net.Conn, nerr net.Error)

HandleRequest handles requests from streaming clients. It tries to extract the path and if meta data is supported. Once a request has been successfully decoded ServeRequest is called. The connection is closed once HandleRequest finishes.

func (*DefaultRequestHandler) SetDebugLogger

func (drh *DefaultRequestHandler) SetDebugLogger(logger DebugLogger)

SetDebugLogger sets the debug logger for this request handler.

type Playlist

type Playlist interface {

	/*
	   Name is the name of the playlist.
	*/
	Name() string

	/*
	   ContentType returns the content type of this playlist e.g. audio/mpeg.
	*/
	ContentType() string

	/*
	   Artist returns the artist which is currently playing.
	*/
	Artist() string

	/*
	   Title returns the title which is currently playing.
	*/
	Title() string

	/*
		Frame returns the current audio frame which is playing.
	*/
	Frame() ([]byte, error)

	/*
		ReleaseFrame releases a frame which has been written to the client.
	*/
	ReleaseFrame([]byte)

	/*
		Finished returns if the playlist has finished playing.
	*/
	Finished() bool

	/*
		Close any open files by this playlist and reset the current pointer. After this
		call the playlist can be played again unless an error is returned.
	*/
	Close() error
}

Playlist is an object which provides a request handler with a constant stream of bytes and meta information about the current playing title.

type PlaylistFactory

type PlaylistFactory interface {

	/*
		Playlist returns a playlist for a given path.
	*/
	Playlist(path string, shuffle bool) Playlist
}

PlaylistFactory produces a Playlist for a given path.

type Server

type Server struct {
	Running     bool                   // Flag indicating if the server is running
	Handler     ConnectionHandler      // Handler function for new  connections
	DebugOutput bool                   // Enable additional debugging output
	LogPrint    func(v ...interface{}) // Print logger method.
	// contains filtered or unexported fields
}

Server data structure

func NewServer

func NewServer(handler ConnectionHandler) *Server

NewServer creates a new DudelDu server.

func (*Server) IsDebugOutputEnabled

func (ds *Server) IsDebugOutputEnabled() bool

IsDebugOutputEnabled returns true if debug output is enabled.

func (*Server) PrintDebug

func (ds *Server) PrintDebug(v ...interface{})

PrintDebug will print debug output if `DebugOutput` is enabled.

func (*Server) Run

func (ds *Server) Run(laddr string, wgStatus *sync.WaitGroup) error

Run starts the DudelDu Server which can be stopped via ^C (Control-C).

laddr should be the local address which should be given to net.Listen. wgStatus is an optional wait group which will be notified once the server is listening and once the server has shutdown.

This function will not return unless the server is shutdown.

func (*Server) Shutdown

func (ds *Server) Shutdown()

Shutdown sends a shutdown signal.

Directories

Path Synopsis
Package playlist contains the default playlist implementation.
Package playlist contains the default playlist implementation.
DudelDu main entry point for the standalone server.
DudelDu main entry point for the standalone server.