George Peter Staplin Mon Sep 17, 2007 I wanted to listen to some music I had, and I looked at the available software such as icecast, and some others, and I was disappointed by the complexity. I decided it was easier to build my own than read the many pages of documentation and config files to make sure I had a secure audio server.
So this is what I created. It works with WMP, xmms, and mplayer over a network.
Usage on the client side:
mplayer http://localhost:6666
Server-side usage:
tclsh8.5 audio_server.tcl /path/to/*.mp3
By the way, it's easy to change it to use ogg or flac.
set ::clients [list]
set ::songs [list]
set ::song_offset 0
set ::song_fd ""
set ::packet ""
array set ::ready {}
proc ready sock {
global ready clients
set ready($sock) $sock
if {[array size ready] >= [llength $clients]} {
foreach {key sock} [array get ready] {
send-data $sock
}
array unset ready
array set ready {}
advance
}
}
set ::counter 1
proc send-data sock {
global packet clients
if {[catch {puts -nonewline $sock $packet} err]} {
puts stderr $err
catch {close $sock}
set i [lsearch -exact $clients $sock]
set clients [lreplace $clients $i $i]
}
puts "sent packet to $sock $::counter"
incr ::counter
}
proc advance {} {
global packet song_fd song_offset songs
if {"" eq $song_fd} {
set song_fd [open [lindex $songs $song_offset] r]
fconfigure $song_fd -translation binary
}
set packet [read $song_fd 4096]
if {[eof $song_fd]} {
catch {close $song_fd}
set song_fd ""
incr song_offset
if {$song_offset >= [llength $songs]} {
set song_offset 0
}
}
}
proc accept {sock addr port} {
global clients
lappend clients $sock
fconfigure $sock -blocking 1 -translation binary
puts "Connection from ${addr}:$port"
if {[catch {puts -nonewline $sock "HTTP/1.1 200 OK\r\n"
puts -nonewline $sock "Content-Type: audio/mpeg\r\n"
puts -nonewline $sock "\r\n"
flush $sock} err]} {
puts stderr $err
set i [lsearch -exact $clients $sock]
set clients [lreplace $clients $i $i]
catch {close $sock}
}
fileevent $sock writable [list ready $sock]
}
proc main {argc argv} {
set ::songs $argv
socket -server accept 6666
advance
vwait _forever_
}
main $::argc $::argv