This repository has been archived by the owner on Dec 10, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
shoutcast.go
100 lines (86 loc) · 2.46 KB
/
shoutcast.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package shoutcast
import (
"bufio"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"reflect"
"strconv"
"strings"
)
// SHOUTcastSource allows you to send audio to a SHOUTcast server
type SHOUTcastSource struct {
host string
port int
password string
headers ICYHeaders
tcpConn *net.TCPConn
}
// ICYHeaders is a struct of the headers to be sent at the start of a broadcast
type ICYHeaders struct {
Name string `icy:"icy-name"`
Bitrate int `icy:"icy-br"`
Genre string `icy:"icy-genre"`
Public bool `icy:"icy-pub"`
ContentType string `icy:"content-type"`
}
// HeaderString gives back the string of headers formatted for SHOUTcast
func (i ICYHeaders) HeaderString() string {
headerString := ""
t := reflect.TypeOf(i)
v := reflect.ValueOf(i)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := ""
if field.Type.String() == "string" {
value = v.Field(i).String()
} else if field.Type.String() == "int" {
value = strconv.FormatInt(v.Field(i).Int(), 10)
} else if field.Type.String() == "bool" {
if v.Field(i).Bool() {
value = "1"
} else {
value = "0"
}
}
headerString += field.Tag.Get("icy") + ":" + value + "\n"
}
return headerString
}
// NewSource creates a new SHOUTCast Source
func NewSource(host string, port int, password string, headers ICYHeaders) SHOUTcastSource {
return SHOUTcastSource{
host: host,
port: port,
password: password,
headers: headers,
}
}
// Start opens the connaction to the server and sends the headers
func (s *SHOUTcastSource) Start() error {
addr, _ := net.ResolveTCPAddr("tcp", s.host+":"+strconv.Itoa(s.port+1))
var err error
s.tcpConn, err = net.DialTCP("tcp", nil, addr)
if err != nil {
return err
}
fmt.Fprintf(s.tcpConn, s.password+"\n")
reply, _ := bufio.NewReader(s.tcpConn).ReadString('\n')
if !strings.Contains(reply, "OK2") {
return errors.New("Non-OK reply: " + reply)
}
// Send headers
fmt.Fprintf(s.tcpConn, s.headers.HeaderString()+"\n")
return nil
}
// SetInput pipes an io.Reader as the source of the stream
func (s *SHOUTcastSource) SetInput(r io.Reader) (int64, error) {
return s.tcpConn.ReadFrom(r)
}
// SetMetatata allows you to set the song and DJ name
func (s *SHOUTcastSource) SetMetatata(title, djname string) {
http.Get("http://" + s.host + ":" + strconv.Itoa(s.port) + "/admin.cgi?mode=updinfo&pass=" + url.QueryEscape(s.password) + "&song=" + url.QueryEscape(title) + "&djname=" + url.QueryEscape(djname))
}