Update Kirika, use new Queue with cancellable entries
continuous-integration/drone/push Build is passing Details

This commit is contained in:
DataHoarder 2022-09-05 17:11:49 +02:00
parent 59b9c25f17
commit 9b634fac0a
Signed by: DataHoarder
SSH Key Fingerprint: SHA256:EnPQOqPpbCa7nzalCEJY2sd9iPluFIBuJu2rDFalACI
6 changed files with 53 additions and 47 deletions

View File

@ -182,7 +182,7 @@ func (a *API) listen() {
type queueResultResponse struct { type queueResultResponse struct {
resultResponse resultResponse
QueueId queue.QueueIdentifier `json:"queue_id"` QueueId queue.Identifier `json:"queue_id"`
} }
a.wg.Add(1) a.wg.Add(1)
@ -261,7 +261,7 @@ func (a *API) listen() {
if e, err := a.getQueueEntryFromBody(body); e != nil { if e, err := a.getQueueEntryFromBody(body); e != nil {
if err = a.queue.AddTrack(e, false); err == nil { if err = a.queue.AddTrack(e, false); err == nil {
result.Success = true result.Success = true
result.QueueId = e.QueueIdentifier result.QueueId = e.Identifier
} else { } else {
resultErr := err.Error() resultErr := err.Error()
result.Reason = &resultErr result.Reason = &resultErr
@ -281,7 +281,7 @@ func (a *API) listen() {
} else if request.Method == "DELETE" { } else if request.Method == "DELETE" {
result := resultResponse{} result := resultResponse{}
if head := a.queue.GetHead(); head != nil { if head := a.queue.GetHead(); head != nil {
result.Success = a.queue.Remove(head.QueueIdentifier) result.Success = a.queue.Remove(head.Identifier)
} }
jsonData, _ := json.Marshal(result) jsonData, _ := json.Marshal(result)
@ -297,7 +297,7 @@ func (a *API) listen() {
if e, err := a.getQueueEntryFromBody(body); e != nil { if e, err := a.getQueueEntryFromBody(body); e != nil {
if err = a.queue.AddTrack(e, true); err == nil { if err = a.queue.AddTrack(e, true); err == nil {
result.Success = true result.Success = true
result.QueueId = e.QueueIdentifier result.QueueId = e.Identifier
} else { } else {
resultErr := err.Error() resultErr := err.Error()
result.Reason = &resultErr result.Reason = &resultErr
@ -317,7 +317,7 @@ func (a *API) listen() {
} else if request.Method == "DELETE" { } else if request.Method == "DELETE" {
result := resultResponse{} result := resultResponse{}
if head := a.queue.GetTail(); head != nil { if head := a.queue.GetTail(); head != nil {
result.Success = a.queue.Remove(head.QueueIdentifier) result.Success = a.queue.Remove(head.Identifier)
} }
jsonData, _ := json.Marshal(result) jsonData, _ := json.Marshal(result)
@ -334,7 +334,7 @@ func (a *API) listen() {
result := resultResponse{} result := resultResponse{}
for _, e := range a.queue.GetQueue() { for _, e := range a.queue.GetQueue() {
a.queue.Remove(e.QueueIdentifier) a.queue.Remove(e.Identifier)
} }
result.Success = true result.Success = true
@ -350,7 +350,7 @@ func (a *API) listen() {
if i, err := strconv.ParseInt(pathSegments[2], 10, 0); err == nil { if i, err := strconv.ParseInt(pathSegments[2], 10, 0); err == nil {
result := resultResponse{} result := resultResponse{}
result.Success = a.queue.Remove(queue.QueueIdentifier(i)) result.Success = a.queue.Remove(queue.Identifier(i))
jsonData, _ := json.Marshal(result) jsonData, _ := json.Marshal(result)
writer.Write(jsonData) writer.Write(jsonData)

2
go.mod
View File

@ -3,7 +3,7 @@ module git.gammaspectra.live/S.O.N.G/MeteorLight
go 1.19 go 1.19
require ( require (
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220803133829-bf39ddac3ac7 git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220905145717-5b3948f68ccc
github.com/BurntSushi/toml v1.2.0 github.com/BurntSushi/toml v1.2.0
github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086 github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086
github.com/enriquebris/goconcurrentqueue v0.6.3 github.com/enriquebris/goconcurrentqueue v0.6.3

4
go.sum
View File

@ -1,5 +1,5 @@
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220803133829-bf39ddac3ac7 h1:580azkVpYctqZcgT3RGRP7rQJfURXHfD3F4/WzHHKpU= git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220905145717-5b3948f68ccc h1:V3NtzTkIoTWa2U8Pv8ypFap+3B1Axr2TUja7lhYwfMM=
git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220803133829-bf39ddac3ac7/go.mod h1:t8jY8NqFY2Wwzcyj486u7ox4zyfXnlnoQBgbOzBQdl0= git.gammaspectra.live/S.O.N.G/Kirika v0.0.0-20220905145717-5b3948f68ccc/go.mod h1:IALWR0qk0+O4sxb7vlW9HZssHL4YbtI4ju6UvBDOxOw=
git.gammaspectra.live/S.O.N.G/flacgo v0.0.0-20220726151057-28f458bc5391 h1:us3yKKsnMe0FZVHRSFZCw113ddiNrZgKf5M5PNr3SQ4= git.gammaspectra.live/S.O.N.G/flacgo v0.0.0-20220726151057-28f458bc5391 h1:us3yKKsnMe0FZVHRSFZCw113ddiNrZgKf5M5PNr3SQ4=
git.gammaspectra.live/S.O.N.G/flacgo v0.0.0-20220726151057-28f458bc5391/go.mod h1:ZVHB/7Vrs9xxK1j98+SJ5TRYBc7Q9dIUaNJHEmysZcI= git.gammaspectra.live/S.O.N.G/flacgo v0.0.0-20220726151057-28f458bc5391/go.mod h1:ZVHB/7Vrs9xxK1j98+SJ5TRYBc7Q9dIUaNJHEmysZcI=
git.gammaspectra.live/S.O.N.G/go-alac v0.0.0-20220421115623-d0b3bfe57e0f h1:CxN7zlk5FdAieyRKQSbwBGBsvQ2cDF8JVCODZpzcRkA= git.gammaspectra.live/S.O.N.G/go-alac v0.0.0-20220421115623-d0b3bfe57e0f h1:CxN7zlk5FdAieyRKQSbwBGBsvQ2cDF8JVCODZpzcRkA=

View File

@ -93,7 +93,7 @@ func (l *Listener) Write(packet packetizer.Packet) error {
if metadataPacket, ok := packet.(*metadata.Packet); ok { if metadataPacket, ok := packet.(*metadata.Packet); ok {
queueInfoBuf := make([]byte, binary.MaxVarintLen64) queueInfoBuf := make([]byte, binary.MaxVarintLen64)
n := binary.PutVarint(queueInfoBuf, int64(metadataPacket.TrackEntry.QueueIdentifier)) n := binary.PutVarint(queueInfoBuf, int64(metadataPacket.TrackEntry.Identifier))
if len(l.sliceWriter) >= (cap(l.sliceWriter) - 1) { if len(l.sliceWriter) >= (cap(l.sliceWriter) - 1) {
l.ctx.Fail(errors.New("client ran out of writer buffer")) l.ctx.Fail(errors.New("client ran out of writer buffer"))

View File

@ -100,7 +100,7 @@ func (q *Queue) AddTrack(entry *track.Entry, tail bool) error {
return err return err
} }
startCallback := func(queue *queue.Queue, queueEntry *queue.QueueEntry) { startCallback := func(queue *queue.Queue, queueEntry *queue.Entry) {
if e := q.Get(queueEntry.Identifier); e != nil { //is this needed? if e := q.Get(queueEntry.Identifier); e != nil { //is this needed?
log.Printf("now playing \"%s\": %s - %s (%s)\n", e.Path, e.Metadata.Title, e.Metadata.Artist, e.Metadata.Album) log.Printf("now playing \"%s\": %s - %s (%s)\n", e.Path, e.Metadata.Title, e.Metadata.Artist, e.Metadata.Album)
q.NowPlaying <- e q.NowPlaying <- e
@ -116,11 +116,11 @@ func (q *Queue) AddTrack(entry *track.Entry, tail bool) error {
} }
} }
endCallback := func(queue *queue.Queue, entry *queue.QueueEntry) { endCallback := func(queue *queue.Queue, entry *queue.Entry) {
} }
removeCallback := func(queue *queue.Queue, entry *queue.QueueEntry) { removeCallback := func(queue *queue.Queue, entry *queue.Entry) {
//TODO: carry sample rate error //TODO: carry sample rate error
q.duration.Add(int64((time.Second * time.Duration(entry.ReadSamples.Load())) / time.Duration(entry.Source.GetSampleRate()))) q.duration.Add(int64((time.Second * time.Duration(entry.ReadSamples.Load())) / time.Duration(entry.Source.GetSampleRate())))
@ -145,12 +145,12 @@ func (q *Queue) AddTrack(entry *track.Entry, tail bool) error {
} }
if tail { if tail {
entry.QueueIdentifier = q.audioQueue.AddTail(source, startCallback, endCallback, removeCallback) entry.Identifier = q.audioQueue.AddTail(source, startCallback, endCallback, removeCallback)
} else { } else {
entry.QueueIdentifier = q.audioQueue.AddHead(source, startCallback, endCallback, removeCallback) entry.Identifier = q.audioQueue.AddHead(source, startCallback, endCallback, removeCallback)
} }
entry.Original["queue_id"] = entry.QueueIdentifier entry.Original["queue_id"] = entry.Identifier
if tail || len(q.queue) == 0 { if tail || len(q.queue) == 0 {
q.queue = append(q.queue, entry) q.queue = append(q.queue, entry)
@ -186,11 +186,11 @@ func (q *Queue) GetQueue() (result []*track.Entry) {
return return
} }
func (q *Queue) Get(identifier queue.QueueIdentifier) *track.Entry { func (q *Queue) Get(identifier queue.Identifier) *track.Entry {
q.mutex.RLock() q.mutex.RLock()
defer q.mutex.RUnlock() defer q.mutex.RUnlock()
for _, e := range q.queue { for _, e := range q.queue {
if e.QueueIdentifier == identifier { if e.Identifier == identifier {
return e return e
} }
} }
@ -238,19 +238,26 @@ func (q *Queue) GetTail() *track.Entry {
return nil return nil
} }
func (q *Queue) Remove(identifier queue.QueueIdentifier) bool { func (q *Queue) Remove(identifier queue.Identifier) bool {
q.mutex.Lock() var entry *track.Entry
for i, e := range q.queue { func() {
if e.QueueIdentifier == identifier { defer q.audioQueue.Remove(identifier)
q.queue = append(q.queue[:i], q.queue[i+1:]...) q.mutex.Lock()
q.mutex.Unlock() defer q.mutex.Unlock()
q.audioQueue.Remove(identifier)
e.Close() for i, e := range q.queue {
return true if e.Identifier == identifier {
q.queue = append(q.queue[:i], q.queue[i+1:]...)
entry = e
return
}
} }
}()
if entry != nil {
_ = entry.Close()
return true
} }
q.mutex.Unlock()
q.audioQueue.Remove(identifier)
return false return false
} }
@ -493,30 +500,29 @@ func (q *Queue) HandleRadioRequest(writer http.ResponseWriter, request *http.Req
log.Printf("adding %s client to stream %s (%s, %s, agent \"%s\", buffer %.2f seconds)\n", listenerIdentifier, mount.Mount, request.RemoteAddr, request.Proto, request.Header.Get("user-agent"), float64(sampleBufferLimit)/float64(mount.SampleRate)) log.Printf("adding %s client to stream %s (%s, %s, agent \"%s\", buffer %.2f seconds)\n", listenerIdentifier, mount.Mount, request.RemoteAddr, request.Proto, request.Header.Get("user-agent"), float64(sampleBufferLimit)/float64(mount.SampleRate))
mount.AddListener(mountListener) mount.AddListener(mountListener)
var wgClient sync.WaitGroup ctx := request.Context()
var flusher http.Flusher
if httpFlusher, ok := writer.(http.Flusher); ok {
flusher = httpFlusher
}
wgClient.Add(1) for !requestDone.Done() {
go func() { select {
defer wgClient.Done() case byteSlice := <-writeChannel:
var flusher http.Flusher
if httpFlusher, ok := writer.(http.Flusher); ok {
flusher = httpFlusher
}
for byteSlice := range writeChannel {
if _, err := writer.Write(byteSlice); err != nil { if _, err := writer.Write(byteSlice); err != nil {
requestDone.Fail(err) requestDone.Fail(err)
return break
} }
//try flush //try flush
if flusher != nil { if flusher != nil {
flusher.Flush() flusher.Flush()
} }
case <-ctx.Done():
requestDone.Fail(ctx.Err())
break
} }
}() }
wgClient.Wait()
log.Printf("removing %s client from stream %s\n", listenerIdentifier, mount.Mount) log.Printf("removing %s client from stream %s\n", listenerIdentifier, mount.Mount)
return return

View File

@ -17,9 +17,9 @@ import (
) )
type Entry struct { type Entry struct {
QueueIdentifier queue.QueueIdentifier Identifier queue.Identifier
Path string Path string
Metadata struct { Metadata struct {
Title interface{} `json:"title"` Title interface{} `json:"title"`
Album interface{} `json:"album"` Album interface{} `json:"album"`
Artist interface{} `json:"artist"` Artist interface{} `json:"artist"`