streaming

This commit is contained in:
gauthiier 2019-01-03 14:21:24 +01:00
parent 5e4f9b8862
commit 683cce60ab
5 changed files with 175 additions and 94 deletions

View File

@ -8,15 +8,9 @@ import (
"../icecast" "../icecast"
) )
// type stream_t struct { type Next func() (string, error)
// filepath string
// bitrate int
// channels int
// encoding_src string
// encoding_dst string
// }
func Play(filename string) { func Start(next_cb Next) {
sig := make(chan os.Signal, 1) sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, os.Kill) signal.Notify(sig, os.Interrupt, os.Kill)
@ -26,41 +20,51 @@ func Play(filename string) {
channels := 1 channels := 1
bytes_per_sec := int(samplerate) * channels * bytes_per_sample bytes_per_sec := int(samplerate) * channels * bytes_per_sample
r, e := os.Open(filename)
chk(e)
defer r.Close()
_, er := icecast.Connect() _, er := icecast.Connect()
chk(er) chk(er)
audio := make([]byte, 2 * 1024) audio := make([]byte, 2 * 1024)
dt := time.Second * time.Duration(len(audio)) / time.Duration(bytes_per_sec) dt := time.Second * time.Duration(len(audio)) / time.Duration(bytes_per_sec)
now := time.Now() for fname, exit := next_cb(); exit == nil; fname, exit = next_cb() {
for { r, e := os.Open(fname)
chk(e)
defer r.Close()
n, err := r.Read(audio) now := time.Now()
if n == 0 {
break
}
chk(err)
icecast.Send(audio) for {
n, err := r.Read(audio)
if n == 0 {
break
}
chk(err)
pre := time.Now()
icecast.Send(audio)
post := time.Now()
lag := time.Duration((post.Sub(pre)))
select {
case <-sig:
return
default:
}
dt = (time.Second * time.Duration(n) / time.Duration(bytes_per_sec)) - lag
time.Sleep(dt)
select {
case <-sig:
return
default:
} }
time.Sleep(dt) fmt.Println(time.Duration(time.Now().Sub(now)))
} }
fmt.Println(time.Duration(time.Now().Sub(now)))
} }

View File

@ -13,12 +13,15 @@ import (
var pln = log.Println var pln = log.Println
type Pop func(*Playlist)
type Playlist struct { type Playlist struct {
NAME string NAME string
CTRACK config.Track_t CTRACK config.Track_t
CALBUM config.Album_t CALBUM config.Album_t
LIST []uint32 LIST []uint32
MAX int MAX int
CALLB Pop
} }
type PrettyPlaylist struct { type PrettyPlaylist struct {
@ -29,6 +32,19 @@ type PrettyPlaylist struct {
MAX int MAX int
} }
type MinimalTrack struct {
ID string `json:"id"`
NAME string `json:"name"`
MAKER string `json:"maker"`
ALBUM string `json:"album"`
}
type MinimalPlaylist struct {
NAME string `json:"name"`
CTRACK string `json:"ctrack"`
CALBUM string `json:"calbum"`
LIST []MinimalTrack `json:"list"`
}
func MakeRandom(name string, max int) (*Playlist, error) { func MakeRandom(name string, max int) (*Playlist, error) {
err := archive.Build() err := archive.Build()
@ -80,19 +96,22 @@ func (pp *PrettyPlaylist) Unpretty() *Playlist {
p := &Playlist{NAME: pp.NAME, CTRACK: pp.CTRACK, CALBUM: pp.CALBUM, MAX: pp.MAX} p := &Playlist{NAME: pp.NAME, CTRACK: pp.CTRACK, CALBUM: pp.CALBUM, MAX: pp.MAX}
p.LIST = make([]uint32, len(pp.LIST)) p.LIST = make([]uint32, len(pp.LIST))
for i := 0; i < len(pp.LIST); i++ { for i := 0; i < len(pp.LIST); i++ {
p.LIST = append(p.LIST, pp.LIST[i].ID) p.LIST[i] = pp.LIST[i].ID
} }
return p return p
} }
// type PrettyPlaylist struct { func (p *Playlist) Minimal() *MinimalPlaylist {
// NAME string mp := &MinimalPlaylist{NAME: p.NAME, CTRACK: p.CTRACK.NAME}
// CTRACK config.Track_t mp.CALBUM = p.CALBUM.MAKER + " - " + p.CALBUM.NAME
// CALBUM config.Album_t mp.LIST = make([]MinimalTrack, len(p.LIST))
// LIST []config.Track_t for i := 0; i < len(p.LIST); i++ {
// MAX int track := archive.Archive_map[p.LIST[i]]
// } strid := strconv.FormatUint(uint64(track.ID), 10)
mp.LIST[i] = MinimalTrack{ID: strid, NAME: track.NAME, MAKER: track.MAKER, ALBUM: track.ALBUM}
}
return mp
}
func (pp *PrettyPlaylist) Print() { func (pp *PrettyPlaylist) Print() {
@ -115,9 +134,9 @@ func print(slice []uint32) {
// https://github.com/golang/go/wiki/SliceTricks // https://github.com/golang/go/wiki/SliceTricks
// https://stackoverflow.com/questions/33834742/remove-and-adding-elements-to-array-in-go-lang // https://stackoverflow.com/questions/33834742/remove-and-adding-elements-to-array-in-go-lang
func (p *Playlist) Pop() error { func (p *Playlist) Pop() (string, error) {
if len(p.LIST) == 0 { if len(p.LIST) == 0 {
return errors.New("Playlist is empty") return "", errors.New("Playlist is empty")
} }
t := p.LIST[0] t := p.LIST[0]
@ -130,7 +149,11 @@ func (p *Playlist) Pop() error {
p.CTRACK = archive.Archive_map[t] p.CTRACK = archive.Archive_map[t]
p.CALBUM = config.Xcfg.Archive.ALBUMS[p.CTRACK.AID] p.CALBUM = config.Xcfg.Archive.ALBUMS[p.CTRACK.AID]
return nil if p.CALLB != nil {
p.CALLB(p)
}
return p.CTRACK.PATH, nil
} }
func (p *Playlist) Push(track_id uint32) error { func (p *Playlist) Push(track_id uint32) error {
@ -191,26 +214,43 @@ func (p *Playlist) Move(track_id uint32, at_index int) error {
return errors.New("Invalid track ID") return errors.New("Invalid track ID")
} }
slice_head := p.LIST[:k] // pln("k: " + strconv.Itoa(k))
slice_move := p.LIST[k+1:at_index+1] // pln("at_index: " + strconv.Itoa(at_index))
slice_tail := make([]uint32, len(p.LIST[at_index+1:])) // pln("------")
copy(slice_tail, p.LIST[at_index+1:])
// slice_move = append(slice_move, track_id) var slice_head, slice_move, slice_tail []uint32
if k < at_index {
slice_head = make([]uint32, len(p.LIST[:k]))
copy(slice_head, p.LIST[:k])
// slice_head = p.LIST[:k]
slice_move = make([]uint32, len(p.LIST[k+1:at_index+1]))
copy(slice_move, p.LIST[k+1:at_index+1])
// slice_move = p.LIST[k:at_index]
slice_tail = make([]uint32, len(p.LIST[at_index+1:]))
copy(slice_tail, p.LIST[at_index+1:])
p.LIST = append(slice_head, append(append(slice_move, track_id), slice_tail...)...)
} else if k > at_index {
slice_head = make([]uint32, len(p.LIST[:at_index]))
copy(slice_head, p.LIST[:at_index])
// slice_head = p.LIST[:at_index]
slice_move = make([]uint32, len(p.LIST[at_index:k]))
copy(slice_move, p.LIST[at_index:k])
// slice_tail = p.LIST[k+1:]
slice_tail = make([]uint32, len(p.LIST[k+1:]))
copy(slice_tail, p.LIST[k+1:])
p.LIST = append(append(append(slice_head, track_id), slice_move...), slice_tail...)
}
pln("from_index: " + strconv.Itoa(k))
pln("at_index: " + strconv.Itoa(at_index))
pln("------")
pln("slice head: ")
print(slice_head)
pln("slice move: ")
print(slice_move)
pln("** ")
pln("slice tail: ")
print(slice_tail)
pln("...........................")
p.LIST = append(slice_head, append(append(slice_move, track_id), slice_tail...)...) // pln("slice head: ")
// print(slice_head)
// pln("slice move: ")
// print(slice_move)
// pln("** ")
// pln("slice tail: ")
// print(slice_tail)
// pln("...........................")
return nil return nil
} }

View File

@ -5,19 +5,25 @@ import (
"log" "log"
"net/http" "net/http"
"./config" "./config"
"./audio"
"./playlist" "./playlist"
"./www" "./www"
) )
var pln = fmt.Println var pln = fmt.Println
var p *playlist.Playlist = nil
func main() { func main() {
config.Loadconfig("config.ini") config.Loadconfig("config.ini")
p, err := playlist.MakeRandom("YOYO", 10) p, err := playlist.MakeRandom("YOYO", 10)
if err != nil { if err != nil {
panic(err) panic(err)
} }
p.Pop()
www.Init(p) www.Init(p)
go audio.Start(p.Pop)
log.Fatal(http.ListenAndServe(":8718", nil)) log.Fatal(http.ListenAndServe(":8718", nil))
} }

View File

@ -19,13 +19,10 @@
console.log("update") console.log("update")
list = Array.from(document.querySelectorAll('#sortable>li')); list = Array.from(document.querySelectorAll('#sortable>li'));
var i = list.indexOf(u.item[0]) var i = list.indexOf(u.item[0])
console.log(u.item.attr("id") + " is now " + i)
on_update_operation(u.item.attr("id"), i) on_update_operation(u.item.attr("id"), i)
} }
}); });
$( "#sortable" ).disableSelection(); $( "#sortable" ).disableSelection();
// connect to ppop
sock = new WebSocket("ws://localhost:8718/ppop"); sock = new WebSocket("ws://localhost:8718/ppop");
sock.onopen = function() { sock.onopen = function() {
console.log("ppop open") console.log("ppop open")
@ -34,31 +31,63 @@
console.log("ppop closed") console.log("ppop closed")
sock = new WebSocket("ws://localhost:8718/ppop"); sock = new WebSocket("ws://localhost:8718/ppop");
} }
sock.onmessage = function(msg) { sock.onmessage = function(msg) {
console.log(msg.data) check_fix_list(JSON.parse(msg.data))
} }
// setInterval(function() {
// sock.send(JSON.stringify({"op": "tick", "id": "0", "index": 0}));
// },3000);
} ); } );
var sock = null; var sock = null;
function on_update_operation(id, index) { function on_update_operation(id, index) {
if(sock) { if(sock) {
console.log("sending") console.log("sending")
sock.send(JSON.stringify({"op": "move", "id": id, "index": index})); sock.send(JSON.stringify({"op": "move", "id": id, "index": index}))
} }
} }
function check_fix_list(playlist) {
console.log(playlist)
$("#pname").text("Playlist: " + playlist.name)
$("#tname").text("Current Track: " + playlist.ctrack)
$("#aname").text("Current Album: " + playlist.calbum)
list = Array.from(document.querySelectorAll('#sortable>li'))
console.log("length ul: " + list.length)
console.log("length playlist: " + playlist.list.length)
for (let i = 0; i < list.length; i++) {
if(i >= playlist.list.length) {
break
} else if (list[i].id != playlist.list[i]["id"]) {
console.log("difference at index: " + i)
list[i].setAttribute("id", playlist.list[i]["id"])
list[i].innerHTML = "<span>" + playlist.list[i]["maker"] +
" - " + playlist.list[i]["album"] +
" - " + playlist.list[i]["name"] + "</span>" ;
}
}
var ul = document.getElementById('sortable');
if(list.length > playlist.list.length) {
for(let i = playlist.list.length; i < list.length; i++) {
ul.removeChild(list[i])
}
} else if (list.length < playlist.list.length) {
}
console.log("synched!!")
}
</script> </script>
<title>Radiodiodio</title> <title>Radiodiodio</title>
</head> </head>
<body> <body>
<h1>Playlist: {{.NAME}}</h1> <h1 id="pname">Playlist: {{.NAME}}</h1>
<audio controls src="http://192.168.1.80:8088/wwww"></audio>
<h2>Current Track: {{.CTRACK.NAME}} </h2> <h2 id="tname">Current Track: {{.CTRACK.NAME}}</h2>
<h2>Current Album : {{.CALBUM.NAME}} - {{.CALBUM.MAKER}}</h2> <h2 id="aname">Current Album : {{.CALBUM.NAME}} - {{.CALBUM.MAKER}}</h2>
<ul id="sortable"> <ul id="sortable">
{{range $.LIST}} {{range $.LIST}}

View File

@ -10,9 +10,11 @@ import (
) )
// todo: hub - https://stackoverflow.com/questions/31532652/go-websocket-send-all-clients-a-message // todo: hub - https://stackoverflow.com/questions/31532652/go-websocket-send-all-clients-a-message
var wsc *websocket.Conn
var pp *playlist.PrettyPlaylist
var p *playlist.Playlist var p *playlist.Playlist
var pp *playlist.PrettyPlaylist
var mp *playlist.MinimalPlaylist
var pln = log.Println var pln = log.Println
@ -29,7 +31,9 @@ var upgrader = websocket.Upgrader{
func Init(playlist *playlist.Playlist) { func Init(playlist *playlist.Playlist) {
p = playlist p = playlist
p.CALLB = pop_callback
pp = p.Pretty() pp = p.Pretty()
mp = p.Minimal()
http.HandleFunc("/pp", pp_handler) http.HandleFunc("/pp", pp_handler)
http.HandleFunc("/ppop", pp_operations) http.HandleFunc("/ppop", pp_operations)
} }
@ -51,6 +55,7 @@ func pp_operations(w http.ResponseWriter, r *http.Request) {
pln(err) pln(err)
return return
} }
wsc = c // this should be hub
go readop(c) go readop(c)
} }
@ -66,27 +71,24 @@ func readop(c *websocket.Conn) {
if id, err := strconv.ParseUint(opdata.ID, 10, 32); err == nil { if id, err := strconv.ParseUint(opdata.ID, 10, 32); err == nil {
p.Move(uint32(id), opdata.INDEX) p.Move(uint32(id), opdata.INDEX)
pp = p.Pretty() pp = p.Pretty()
pp.Print() mp = p.Minimal()
// pp.Print()
} }
} }
pln(opdata.OP) if err := c.WriteJSON(mp); err != nil {
pln(opdata.ID)
pln(opdata.INDEX)
if err := c.WriteJSON(opdata); err != nil {
pln(err) pln(err)
return //connection lost? return //connection lost?
} }
} }
} }
// func pp_operations(ws *websocket.Conn) { func pop_callback(list *playlist.Playlist) {
// opdata := &op_t{} if list == p {
// if err := websocket.JSON.Receive(ws, &opdata); err != nil { pp = p.Pretty()
// pln(err) mp = p.Minimal()
// } if wsc != nil {
// // websocket.JSON.Send(ws, "ok") wsc.WriteJSON(mp) // this should be hub broadcasted
// pln(opdata.OP) }
// pln(opdata.ID) }
// pln(opdata.INDEX) }
// }