206 lines
4.1 KiB
Go
206 lines
4.1 KiB
Go
|
|
package icecast
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"encoding/base64"
|
||
|
|
"net"
|
||
|
|
"net/http"
|
||
|
|
"net/url"
|
||
|
|
"bufio"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
"errors"
|
||
|
|
"strconv"
|
||
|
|
"io/ioutil"
|
||
|
|
"../config"
|
||
|
|
"../socket"
|
||
|
|
)
|
||
|
|
|
||
|
|
var connected bool = false
|
||
|
|
var stream_socket net.Conn
|
||
|
|
var status int = 0
|
||
|
|
var server_msg string
|
||
|
|
|
||
|
|
var pln = fmt.Println
|
||
|
|
var spf = fmt.Sprintf
|
||
|
|
|
||
|
|
|
||
|
|
func Connect() (net.Conn, error){
|
||
|
|
|
||
|
|
if connected {
|
||
|
|
return stream_socket, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
var sock net.Conn
|
||
|
|
host := config.Xcfg.Server.ADDR + ":" + strconv.Itoa(config.Xcfg.Server.PORT)
|
||
|
|
sock, err := net.Dial("tcp", host)
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
connected = false
|
||
|
|
return sock, err
|
||
|
|
}
|
||
|
|
|
||
|
|
time.Sleep(time.Second)
|
||
|
|
|
||
|
|
// doing connection BUTT style (i.e. multiple sends)
|
||
|
|
// icecast only for now
|
||
|
|
// try PUT method
|
||
|
|
|
||
|
|
mount := config.Xcfg.Server.MOUNT
|
||
|
|
s := spf("PUT %s HTTP/1.1\r\n", mount)
|
||
|
|
if mount[0] != '/' {
|
||
|
|
s = spf("PUT /%s HTTP/1.1\r\n", mount)
|
||
|
|
}
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = spf("%s:%s", config.Xcfg.Server.USR, config.Xcfg.Server.PWD)
|
||
|
|
sb64 := "Authorization: Basic " + base64.StdEncoding.EncodeToString([]byte(s)) + "\r\n"
|
||
|
|
err = socket.Send(sock, []byte(sb64))
|
||
|
|
|
||
|
|
s = "User-Agent: radiodiodio/v0.0\r\n"
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = "Content-Type: audio/mp3\r\n"
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = spf("ice-name: %s\r\n", config.Xcfg.Ice.NAME)
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = spf("ice-public: %s\r\n", config.Xcfg.Ice.PUB)
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = spf("ice-url: %s\r\n", config.Xcfg.Ice.URL)
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = spf("ice-genre: %s\r\n", config.Xcfg.Ice.GENRE)
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = spf("ice-description: %s\r\n", config.Xcfg.Ice.DESC)
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = "ice-audio-info: ice-bitrate=192000; ice-channels=2; ice-samplerate=44100\r\n"
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
s = "\r\n"
|
||
|
|
err = socket.Send(sock, []byte(s))
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
pln("error: sending PUT to the icecast server")
|
||
|
|
connected = false
|
||
|
|
return sock, err
|
||
|
|
}
|
||
|
|
|
||
|
|
time.Sleep(time.Second)
|
||
|
|
|
||
|
|
resp, err := socket.Recv(sock)
|
||
|
|
if err != nil {
|
||
|
|
pln("error: receiving response from the icecast server")
|
||
|
|
connected = false
|
||
|
|
return sock, err
|
||
|
|
}
|
||
|
|
|
||
|
|
status, server_msg, err := read_http_response(resp)
|
||
|
|
|
||
|
|
if status != 200 {
|
||
|
|
connected = false
|
||
|
|
return sock, errors.New("Icecast connection failed: " + strconv.Itoa(status) + " - " + server_msg)
|
||
|
|
}
|
||
|
|
|
||
|
|
pln("YAYAY!!")
|
||
|
|
|
||
|
|
connected = true
|
||
|
|
stream_socket = sock
|
||
|
|
|
||
|
|
return sock, nil
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
func Disconnect() {
|
||
|
|
stream_socket.Close()
|
||
|
|
connected = false
|
||
|
|
}
|
||
|
|
|
||
|
|
func Send(buff []byte) error {
|
||
|
|
if !connected {
|
||
|
|
return errors.New("Not connected to Icecast server")
|
||
|
|
}
|
||
|
|
err := socket.Send(stream_socket, buff)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
func Update() error {
|
||
|
|
|
||
|
|
host := config.Xcfg.Server.ADDR + ":" + strconv.Itoa(config.Xcfg.Server.PORT)
|
||
|
|
track := url.QueryEscape(config.Xcfg.Track.NAME)
|
||
|
|
mount := config.Xcfg.Server.MOUNT
|
||
|
|
if mount[0] != '/' {
|
||
|
|
mount = "/" + mount
|
||
|
|
}
|
||
|
|
|
||
|
|
s := spf("%s:%s", config.Xcfg.Server.USR, config.Xcfg.Server.PWD)
|
||
|
|
sb64 := "Basic " + base64.StdEncoding.EncodeToString([]byte(s))
|
||
|
|
|
||
|
|
header := "GET /admin/metadata?mode=updinfo&mount=" + mount + "&song=" + track + " HTTP/1.0\r\n" +
|
||
|
|
"User-Agent: radiodiodio/v0.0\r\n" +
|
||
|
|
"Authorization: " + sb64 + "\r\n" +
|
||
|
|
"\r\n"
|
||
|
|
|
||
|
|
pln(host)
|
||
|
|
pln(header)
|
||
|
|
|
||
|
|
var sock net.Conn
|
||
|
|
sock, err := net.Dial("tcp", host)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
time.Sleep(time.Second)
|
||
|
|
|
||
|
|
err = socket.Send(sock, []byte(header))
|
||
|
|
|
||
|
|
time.Sleep(time.Second)
|
||
|
|
|
||
|
|
defer sock.Close()
|
||
|
|
|
||
|
|
resp, err := socket.Recv(sock)
|
||
|
|
if err != nil {
|
||
|
|
pln("error: receiving response from the icecast server")
|
||
|
|
connected = false
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
status, server_msg, err := read_http_response(resp)
|
||
|
|
|
||
|
|
if status != 200 {
|
||
|
|
connected = false
|
||
|
|
return errors.New("Icecast connection failed: " + strconv.Itoa(status) + " - " + server_msg)
|
||
|
|
} else {
|
||
|
|
pln(server_msg)
|
||
|
|
}
|
||
|
|
|
||
|
|
return err
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
func read_http_response(raw_resp []byte) (int, string, error) {
|
||
|
|
|
||
|
|
reader := bufio.NewReader(strings.NewReader(string(raw_resp)))
|
||
|
|
resp, err := http.ReadResponse(reader, nil)
|
||
|
|
if err != nil {
|
||
|
|
return 0, "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
status := resp.StatusCode
|
||
|
|
|
||
|
|
defer resp.Body.Close()
|
||
|
|
body, er := ioutil.ReadAll(resp.Body)
|
||
|
|
if er != nil {
|
||
|
|
return status, "", er
|
||
|
|
}
|
||
|
|
|
||
|
|
return status, string(body), nil
|
||
|
|
|
||
|
|
}
|
||
|
|
|