Skip to content

romantomjak/shoutcast

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

shoutcast

Build Status

Go interface for SHOUTcast streaming protocol.


Example SHOUTcast client:

package main

import (
    "io"

    mp3 "github.com/hajimehoshi/go-mp3"
    "github.com/hajimehoshi/oto"

    "github.com/romantomjak/shoutcast"
)

func main() {
    // open stream
    stream, err := shoutcast.Open("http://streamingp.shoutcast.com/TomorrowlandOneWorldRadio")
    if err != nil {
        panic(err)
    }
    
    // optionally register a callback function to be called when song changes
    stream.MetadataCallbackFunc = func(m *shoutcast.Metadata) {
        println("Now listening to: ", m.StreamTitle)
    }

    // setup mp3 decoder
    decoder, err := mp3.NewDecoder(stream)
    if err != nil {
        panic(err)
    }
    defer decoder.Close()

    // initialise audio player
    player, err := oto.NewPlayer(decoder.SampleRate(), 2, 2, 8192)
    if err != nil {
        panic(err)
    }
    defer player.Close()

    // enjoy the music
    if _, err := io.Copy(player, decoder); err != nil {
        panic(err)
    }
}

SHOUTcast protocol

Very little information is available about how the streaming technology actually works. Everything in this repo was pieced together from random sites and Wayback Machine archives.

The protocol itself is built on top of HTTP. The client sends information about itself in the form of HTTP headers, and if it can handle title streaming it also sends and extra header:

icy-metadata: 1

This header signifies that the client has the ability to understand the title streaming tags coming from the server. When set, the server will embed metadata about the stream at periodic intervals (once every icy-metaint bytes) in the encoded audio stream itself.

The value of icy-metaint is decided by the shoutcast server configuration and is sent to the client as part of the initial reply.

The first byte of that metadata block tells you the length of the data. A length of 0 means there is no updated metadata.

License

MIT