|
|
|
@ -100,7 +100,7 @@ func (q *Queue) AddTrack(entry *track.Entry, tail bool) error {
|
|
|
|
|
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?
|
|
|
|
|
log.Printf("now playing \"%s\": %s - %s (%s)\n", e.Path, e.Metadata.Title, e.Metadata.Artist, e.Metadata.Album)
|
|
|
|
|
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
|
|
|
|
|
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 {
|
|
|
|
|
entry.QueueIdentifier = q.audioQueue.AddTail(source, startCallback, endCallback, removeCallback)
|
|
|
|
|
entry.Identifier = q.audioQueue.AddTail(source, startCallback, endCallback, removeCallback)
|
|
|
|
|
} 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 {
|
|
|
|
|
q.queue = append(q.queue, entry)
|
|
|
|
@ -186,11 +186,11 @@ func (q *Queue) GetQueue() (result []*track.Entry) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (q *Queue) Get(identifier queue.QueueIdentifier) *track.Entry {
|
|
|
|
|
func (q *Queue) Get(identifier queue.Identifier) *track.Entry {
|
|
|
|
|
q.mutex.RLock()
|
|
|
|
|
defer q.mutex.RUnlock()
|
|
|
|
|
for _, e := range q.queue {
|
|
|
|
|
if e.QueueIdentifier == identifier {
|
|
|
|
|
if e.Identifier == identifier {
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -238,19 +238,26 @@ func (q *Queue) GetTail() *track.Entry {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (q *Queue) Remove(identifier queue.QueueIdentifier) bool {
|
|
|
|
|
q.mutex.Lock()
|
|
|
|
|
for i, e := range q.queue {
|
|
|
|
|
if e.QueueIdentifier == identifier {
|
|
|
|
|
q.queue = append(q.queue[:i], q.queue[i+1:]...)
|
|
|
|
|
q.mutex.Unlock()
|
|
|
|
|
q.audioQueue.Remove(identifier)
|
|
|
|
|
e.Close()
|
|
|
|
|
return true
|
|
|
|
|
func (q *Queue) Remove(identifier queue.Identifier) bool {
|
|
|
|
|
var entry *track.Entry
|
|
|
|
|
func() {
|
|
|
|
|
defer q.audioQueue.Remove(identifier)
|
|
|
|
|
q.mutex.Lock()
|
|
|
|
|
defer q.mutex.Unlock()
|
|
|
|
|
|
|
|
|
|
for i, e := range q.queue {
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -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))
|
|
|
|
|
mount.AddListener(mountListener)
|
|
|
|
|
|
|
|
|
|
var wgClient sync.WaitGroup
|
|
|
|
|
|
|
|
|
|
wgClient.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
defer wgClient.Done()
|
|
|
|
|
var flusher http.Flusher
|
|
|
|
|
if httpFlusher, ok := writer.(http.Flusher); ok {
|
|
|
|
|
flusher = httpFlusher
|
|
|
|
|
}
|
|
|
|
|
ctx := request.Context()
|
|
|
|
|
var flusher http.Flusher
|
|
|
|
|
if httpFlusher, ok := writer.(http.Flusher); ok {
|
|
|
|
|
flusher = httpFlusher
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for byteSlice := range writeChannel {
|
|
|
|
|
for !requestDone.Done() {
|
|
|
|
|
select {
|
|
|
|
|
case byteSlice := <-writeChannel:
|
|
|
|
|
if _, err := writer.Write(byteSlice); err != nil {
|
|
|
|
|
requestDone.Fail(err)
|
|
|
|
|
return
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
//try flush
|
|
|
|
|
if flusher != nil {
|
|
|
|
|
flusher.Flush()
|
|
|
|
|
}
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
requestDone.Fail(ctx.Err())
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
wgClient.Wait()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Printf("removing %s client from stream %s\n", listenerIdentifier, mount.Mount)
|
|
|
|
|
return
|
|
|
|
|