- add documentation
- add more info to README.MD - splited into multiple files
This commit is contained in:
parent
d8155d86e0
commit
951f61fbd4
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
*.exe
|
*.exe
|
||||||
sounds/**
|
sounds/**
|
||||||
|
conf.json
|
||||||
|
28
README.MD
28
README.MD
@ -1,2 +1,28 @@
|
|||||||
|
![Soundr Logo](/resources/logo.svg "Soundr Logo")
|
||||||
|
|
||||||
# Soundr
|
# Soundr
|
||||||
An opensource audio server meant for professional applications
|
Soundr is a simple, open-source, cross-platform audio playing server written in go.
|
||||||
|
It aims to be simple to setup and work in many envoriments. It is also designed to be
|
||||||
|
easy to use and maintain.
|
||||||
|
Soundr is able to play multiple audio files at the same time. It is able to intigrate well as it uses a REST endpoint.
|
||||||
|
Swagger Documentation for that endpoint is available in `apiDocs.yml`.
|
||||||
|
The software it self is written in go and uses the BEEP library. It is made to be shipped as a single executable.
|
||||||
|
Another target was a minimal dependency tree.
|
||||||
|
Initally it was written to be used with [Bitfocus Companion](https://bitfocus.io/companion) in a more professional envoriment. (A client for Companion is currently WiP)
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
Installation is as simple as it gets as it is a single executable.
|
||||||
|
Download one of the releases, drop your sounds into the /sounds folder and run the executable.
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
TODO, no config yet. Soon ports and other settings will be added.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
Drop your sounds into the /sounds. You can play them by sending a GET request to the /v1/play endpoint.
|
||||||
|
You need to know the base64 encoded file name of the sound you want to play. You can get started by querying /v1/list. It will return a list of all sounds with their respective base64 encoded file name.
|
||||||
|
Use that base64 as the `file` parameter in the request.
|
||||||
|
|
||||||
|
**Note**: The sounds must be in the format `*.mp3` (more will be supported soon :tm:).
|
||||||
|
|
||||||
|
# ToDo
|
||||||
|
- [ ] Add support for other audio formats
|
144
apiDocs.yml
Normal file
144
apiDocs.yml
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
openapi: '3.0.2'
|
||||||
|
info:
|
||||||
|
title: Soundr
|
||||||
|
version: '1.0'
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:8082/v1/
|
||||||
|
paths:
|
||||||
|
/play:
|
||||||
|
get:
|
||||||
|
summary: Plays a sound by it's base64'd name. Will load it to buffer first if not already loaded.
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: file
|
||||||
|
description: A base64 encoded version of the file name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: number
|
||||||
|
description: The ID of the playing sound
|
||||||
|
'400':
|
||||||
|
description: Bad Request
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
reason:
|
||||||
|
type: string
|
||||||
|
description: The error message, in this case probably "file not found"
|
||||||
|
/buffer:
|
||||||
|
get:
|
||||||
|
summary: Loads a sound into the buffer.
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: file
|
||||||
|
description: A base64 encoded version of the file name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
|
||||||
|
'400':
|
||||||
|
description: Bad Request
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
reason:
|
||||||
|
type: string
|
||||||
|
description: The error message, in this case probably "file not found"
|
||||||
|
/bufferAll:
|
||||||
|
get:
|
||||||
|
summary: Loads all sounds into the buffer.
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
/stop:
|
||||||
|
get:
|
||||||
|
summary: Stops a given sound by it's ID.
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: id
|
||||||
|
description: The ID of the sound to stop
|
||||||
|
schema:
|
||||||
|
type: number
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
'400':
|
||||||
|
description: Bad Request
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
reason:
|
||||||
|
type: string
|
||||||
|
description: The error message
|
||||||
|
/stopAll:
|
||||||
|
get:
|
||||||
|
summary: Stops all sounds.
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
/current:
|
||||||
|
get:
|
||||||
|
summary: Gets the current playing sound(s).
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
sounds:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: number
|
||||||
|
description: The ID of the sound
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The name of the sound
|
||||||
|
loaded:
|
||||||
|
type: boolean
|
||||||
|
description: Whether the sound is loaded into the buffer
|
||||||
|
/list:
|
||||||
|
get: # TODO REWORK!!!!!
|
||||||
|
summary: Lists all sounds in the buffer.
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
sounds:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The name of the sound
|
||||||
|
base64:
|
||||||
|
type: string
|
||||||
|
description: The base64 version of the name
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
description: The URL to the sound
|
78
handlerFunctions.go
Normal file
78
handlerFunctions.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/faiface/beep"
|
||||||
|
"github.com/faiface/beep/mp3"
|
||||||
|
"github.com/faiface/beep/speaker"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BufferSound(file string) bool {
|
||||||
|
_, ok := streamMap[file]
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("Not in memory, loading")
|
||||||
|
f, err := os.Open("./sounds/" + file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Opened file")
|
||||||
|
streamer, format, _ := mp3.Decode(f)
|
||||||
|
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
|
||||||
|
|
||||||
|
fmt.Println("Decoded file")
|
||||||
|
buffer := beep.NewBuffer(format)
|
||||||
|
buffer.Append(streamer)
|
||||||
|
streamer.Close()
|
||||||
|
fmt.Println("Bufferd file")
|
||||||
|
|
||||||
|
// Save to streamMap
|
||||||
|
streamMap[file] = streamBuf{
|
||||||
|
Streamer: streamer,
|
||||||
|
Format: format,
|
||||||
|
Buffer: buffer,
|
||||||
|
}
|
||||||
|
return (true)
|
||||||
|
} else {
|
||||||
|
return (false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PlaySound(file string, index int) int {
|
||||||
|
playbacks[index] = playback{
|
||||||
|
File: file,
|
||||||
|
IsLoaded: false,
|
||||||
|
Streamer: nil,
|
||||||
|
Control: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Playing sound: " + file)
|
||||||
|
var buffer *beep.Buffer
|
||||||
|
BufferSound(file)
|
||||||
|
buffer = streamMap[file].Buffer
|
||||||
|
streamer := streamMap[file].Streamer
|
||||||
|
|
||||||
|
fmt.Println("Trying to play sound")
|
||||||
|
shot := buffer.Streamer(0, buffer.Len())
|
||||||
|
|
||||||
|
done := make(chan bool)
|
||||||
|
ctrl := &beep.Ctrl{Streamer: beep.Seq(shot, beep.Callback(func() {
|
||||||
|
done <- true
|
||||||
|
})), Paused: false}
|
||||||
|
|
||||||
|
playbacks[index] = playback{
|
||||||
|
File: file,
|
||||||
|
IsLoaded: true,
|
||||||
|
Streamer: streamer,
|
||||||
|
Control: ctrl,
|
||||||
|
}
|
||||||
|
speaker.Play(ctrl)
|
||||||
|
<-done
|
||||||
|
fmt.Println("Finished playing sound: " + file)
|
||||||
|
delete(playbacks, index)
|
||||||
|
return 1
|
||||||
|
}
|
181
resources/logo.svg
Normal file
181
resources/logo.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 29 KiB |
236
soundr.go
236
soundr.go
@ -1,22 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
"github.com/faiface/beep"
|
||||||
"github.com/faiface/beep/mp3"
|
|
||||||
"github.com/faiface/beep/speaker"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type playback struct {
|
type playback struct {
|
||||||
@ -38,198 +30,66 @@ type streamBuf struct {
|
|||||||
Buffer *beep.Buffer
|
Buffer *beep.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Configuration struct {
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
var playbacks map[int]playback
|
var playbacks map[int]playback
|
||||||
var mapMutex = sync.Mutex{}
|
|
||||||
|
|
||||||
var streamMap map[string]streamBuf
|
var streamMap map[string]streamBuf
|
||||||
|
|
||||||
func BufferSound(file string) bool {
|
|
||||||
_, ok := streamMap[file]
|
|
||||||
if !ok {
|
|
||||||
fmt.Println("Not in memory, loading")
|
|
||||||
f, err := os.Open("./sounds/" + file)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Opened file")
|
|
||||||
streamer, format, err := mp3.Decode(f)
|
|
||||||
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
|
|
||||||
|
|
||||||
fmt.Println("Decoded file")
|
|
||||||
buffer := beep.NewBuffer(format)
|
|
||||||
buffer.Append(streamer)
|
|
||||||
streamer.Close()
|
|
||||||
fmt.Println("Bufferd file")
|
|
||||||
|
|
||||||
// Save to streamMap
|
|
||||||
streamMap[file] = streamBuf{
|
|
||||||
Streamer: streamer,
|
|
||||||
Format: format,
|
|
||||||
Buffer: buffer,
|
|
||||||
}
|
|
||||||
return (true)
|
|
||||||
} else {
|
|
||||||
return (false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PlaySound(file string, index int) int {
|
|
||||||
playbacks[index] = playback{
|
|
||||||
File: file,
|
|
||||||
IsLoaded: false,
|
|
||||||
Streamer: nil,
|
|
||||||
Control: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Playing sound: " + file)
|
|
||||||
var buffer *beep.Buffer
|
|
||||||
BufferSound(file)
|
|
||||||
buffer = streamMap[file].Buffer
|
|
||||||
streamer := streamMap[file].Streamer
|
|
||||||
|
|
||||||
fmt.Println("Trying to play sound")
|
|
||||||
shot := buffer.Streamer(0, buffer.Len())
|
|
||||||
|
|
||||||
done := make(chan bool)
|
|
||||||
ctrl := &beep.Ctrl{Streamer: beep.Seq(shot, beep.Callback(func() {
|
|
||||||
done <- true
|
|
||||||
})), Paused: false}
|
|
||||||
|
|
||||||
playbacks[index] = playback{
|
|
||||||
File: file,
|
|
||||||
IsLoaded: true,
|
|
||||||
Streamer: streamer,
|
|
||||||
Control: ctrl,
|
|
||||||
}
|
|
||||||
speaker.Play(ctrl)
|
|
||||||
<-done
|
|
||||||
fmt.Println("Finished playing sound: " + file)
|
|
||||||
delete(playbacks, index)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
fmt.Println("Welcome to Soundr!")
|
||||||
|
|
||||||
playbacks = make(map[int]playback)
|
playbacks = make(map[int]playback)
|
||||||
streamMap = make(map[string]streamBuf)
|
streamMap = make(map[string]streamBuf)
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
// Create /sounds if not exists
|
||||||
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Query().Get("name")))
|
if _, err := os.Stat("./sounds"); os.IsNotExist(err) {
|
||||||
})
|
fmt.Println("Created /sounds folder")
|
||||||
|
os.Mkdir("./sounds", 0777)
|
||||||
|
}
|
||||||
|
|
||||||
http.HandleFunc("/v1/play", func(w http.ResponseWriter, r *http.Request) {
|
// Handle config
|
||||||
w.Header().Set("Content-Type", "application/json")
|
fmt.Println("Opening conf.json")
|
||||||
var cnt = r.URL.Query().Get("file")
|
file, fOpenError := os.Open("conf.json") // Try to open the file
|
||||||
bytArr, err := base64.StdEncoding.DecodeString(cnt)
|
|
||||||
if err != nil {
|
if errors.Is(fOpenError, os.ErrNotExist) { // If it does not exist, create it
|
||||||
log.Fatal(err)
|
fmt.Println("Creating conf.json")
|
||||||
|
file, fOpenError = os.Create("conf.json")
|
||||||
|
if fOpenError != nil {
|
||||||
|
log.Fatal(fOpenError)
|
||||||
}
|
}
|
||||||
fmt.Println(string(bytArr[:]))
|
defer file.Close()
|
||||||
t, err := os.Stat("./sounds/" + string(bytArr[:]))
|
fmt.Println("Writing to conf.json")
|
||||||
t = t
|
// Write the default config to the file
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
json.NewEncoder(file).Encode(Configuration{
|
||||||
var currIndex = len(playbacks)
|
Port: 8080,
|
||||||
fmt.Fprintf(w, "{\"status\":\"ok\", \"id\":%d}", currIndex)
|
})
|
||||||
|
fmt.Println("Wrote to conf.json")
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
// Decode the config
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
configuration := Configuration{}
|
||||||
|
err := decoder.Decode(&configuration)
|
||||||
|
|
||||||
go PlaySound(string(bytArr[:]), currIndex)
|
if err != nil {
|
||||||
|
fmt.Println("error:", err)
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
// Web server stuff
|
||||||
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file not found\"}")
|
// Play route, takes file as parameter, file is base64 encoded
|
||||||
}
|
http.HandleFunc("/v1/play", handlePlay)
|
||||||
|
// Buffer route, buffers file
|
||||||
})
|
http.HandleFunc("/v1/buffer", handleBuffer)
|
||||||
|
http.HandleFunc("/v1/bufferAll", handleBufferAll)
|
||||||
http.HandleFunc("/v1/buffer", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/v1/stop", handleStop)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
http.HandleFunc("/v1/stopAll", handleStopAll)
|
||||||
var cnt = r.URL.Query().Get("file")
|
http.HandleFunc("/v1/current", handleCurrent)
|
||||||
bytArr, err := base64.StdEncoding.DecodeString(cnt)
|
http.HandleFunc("/v1/list", handleListing)
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
t, err := os.Stat("./sounds/" + string(bytArr[:]))
|
|
||||||
t = t
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
fmt.Fprintf(w, "{\"status\":\"ok\"}")
|
|
||||||
go BufferSound(string(bytArr[:]))
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file not found\"}")
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/v1/stopAll", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
playbacks = make(map[int]playback)
|
|
||||||
fmt.Fprintf(w, "{\"status\":\"ok\"}")
|
|
||||||
speaker.Clear()
|
|
||||||
//fmt.Fprintf(w, "{\"status\":\"ok\", \"id\":%d}", currIndex)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/v1/stop", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
var cnt, err = strconv.Atoi(r.URL.Query().Get("id"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"invalid id\"}")
|
|
||||||
}
|
|
||||||
|
|
||||||
value, ok := playbacks[cnt]
|
|
||||||
if !ok {
|
|
||||||
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"audio not playing\"}")
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(w, "{\"status\":\"ok\", \"id\":%d}", value)
|
|
||||||
value.Control.Paused = true
|
|
||||||
value.Control.Streamer = nil
|
|
||||||
delete(playbacks, cnt)
|
|
||||||
}
|
|
||||||
//fmt.Fprintf(w, "{\"status\":\"ok\", \"id\":%d}", currIndex)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/v1/current", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
var tempResultSet map[int]playbackWebReturn
|
|
||||||
tempResultSet = make(map[int]playbackWebReturn)
|
|
||||||
|
|
||||||
for index, element := range playbacks {
|
|
||||||
tempResultSet[index] = playbackWebReturn{File: element.File, IsLoaded: element.IsLoaded, Id: index}
|
|
||||||
}
|
|
||||||
|
|
||||||
j, err := json.Marshal(tempResultSet)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error: %s", err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Println(string(j))
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, string(j))
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/v1/list", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
var temp [][3]string
|
|
||||||
files, err := ioutil.ReadDir("./sounds/")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range files {
|
|
||||||
var soundObj [3]string
|
|
||||||
soundObj[0] = f.Name()
|
|
||||||
soundObj[1] = base64.StdEncoding.EncodeToString([]byte(f.Name()))
|
|
||||||
soundObj[2] = r.URL.Host + "/v1/play?file=" + soundObj[1]
|
|
||||||
temp = append(temp, soundObj)
|
|
||||||
}
|
|
||||||
|
|
||||||
j, err := json.Marshal(temp)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error: %s", err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Println(string(j))
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, string(j))
|
|
||||||
})
|
|
||||||
log.Fatal(http.ListenAndServe(":8081", nil))
|
|
||||||
|
|
||||||
|
fmt.Println("Listening on port " + fmt.Sprint(configuration.Port))
|
||||||
|
log.Fatal(http.ListenAndServe(":"+fmt.Sprint(configuration.Port), nil))
|
||||||
}
|
}
|
||||||
|
208
webRoutes.go
Normal file
208
webRoutes.go
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/faiface/beep/speaker"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handlePlay(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Rejct everything else then GET requests
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method is not supported.", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json") // Set the content type to json
|
||||||
|
var cnt = r.URL.Query().Get("file") // Retrieve the file name from the query string
|
||||||
|
bytArr, err := base64.StdEncoding.DecodeString(cnt) // Decode the base64 string
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := os.Stat("./sounds/" + string(bytArr[:])) // Check if the file exists
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file not found\"}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.IsDir() { // Make sure it is not a folder we are trying to play
|
||||||
|
w.WriteHeader(400)
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"target is folder\"}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var currIndex = len(playbacks) // Create a new index for the playback
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"ok\", \"id\":%d}", currIndex) // Return a JSON object to the user
|
||||||
|
|
||||||
|
go PlaySound(string(bytArr[:]), currIndex) // Play the sound
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Buffering
|
||||||
|
|
||||||
|
func handleBufferAll(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Rejct everything else then GET requests
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method is not supported.", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json") // Set the content type to json
|
||||||
|
|
||||||
|
var temp []string
|
||||||
|
files, err := ioutil.ReadDir("./sounds/") // Read the directory
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// Loop through the files and add the file name to the temp array
|
||||||
|
// Also triggers the buffer process for the file
|
||||||
|
for _, f := range files {
|
||||||
|
temp = append(temp, f.Name())
|
||||||
|
go BufferSound(f.Name())
|
||||||
|
}
|
||||||
|
// Return the amount of files buffered
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"ok\", \"amount\":%d}", len(temp))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleBuffer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Rejct everything else then GET requests
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method is not supported.", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json") // Set the content type to json
|
||||||
|
var cnt = r.URL.Query().Get("file") // Retrieve the file name from the query string
|
||||||
|
bytArr, err := base64.StdEncoding.DecodeString(cnt) // Decode the base64 string
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := os.Stat("./sounds/" + string(bytArr[:])) // Check if the file exists
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"file not found\"}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.IsDir() { // Make sure it is not a folder we are trying to play
|
||||||
|
w.WriteHeader(400)
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"target is folder\"}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"ok\"}")
|
||||||
|
go BufferSound(string(bytArr[:]))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handeling Stop
|
||||||
|
|
||||||
|
func handleStop(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Rejct everything else then GET requests
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method is not supported.", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json") // Set the content type to json
|
||||||
|
var cnt, err = strconv.Atoi(r.URL.Query().Get("id")) // Retrieve the id, first convert it to an int
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"invalid id\"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
value, ok := playbacks[cnt] // Get value from playbacks map
|
||||||
|
if !ok {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"fail\", \"reason\":\"audio not playing\"}")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"ok\"}")
|
||||||
|
// Stop by pausing first then, set the streamer to nil. Finally delete it from the map
|
||||||
|
value.Control.Paused = true
|
||||||
|
value.Control.Streamer = nil
|
||||||
|
delete(playbacks, cnt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleStopAll(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Rejct everything else then GET requests
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method is not supported.", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json") // Set the content type to json
|
||||||
|
|
||||||
|
// Pause and stop all playbacks
|
||||||
|
for _, v := range playbacks {
|
||||||
|
v.Control.Paused = true
|
||||||
|
v.Control.Streamer = nil
|
||||||
|
}
|
||||||
|
speaker.Clear() // Clear the speaker and make it shut up
|
||||||
|
|
||||||
|
// Reset the map
|
||||||
|
playbacks = make(map[int]playback)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "{\"status\":\"ok\"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleCurrent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Rejct everything else then GET requests
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method is not supported.", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json") // Set the content type to json
|
||||||
|
|
||||||
|
var tempResultSet map[int]playbackWebReturn = make(map[int]playbackWebReturn) // Create a new map to store the results
|
||||||
|
// Iterate through the playbacks map and add important information to the tempResultSet map
|
||||||
|
for index, element := range playbacks {
|
||||||
|
tempResultSet[index] = playbackWebReturn{File: element.File, IsLoaded: element.IsLoaded, Id: index}
|
||||||
|
}
|
||||||
|
// Convert the map to a JSON object and return it to the user
|
||||||
|
j, err := json.Marshal(tempResultSet)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Println(string(j))
|
||||||
|
fmt.Fprintf(w, string(j))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleListing(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Rejct everything else then GET requests
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method is not supported.", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json") // Set the content type to json
|
||||||
|
|
||||||
|
var temp [][3]string
|
||||||
|
files, err := ioutil.ReadDir("./sounds/") // Find all files in the sounds directory
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the file data to the temp array
|
||||||
|
for _, f := range files {
|
||||||
|
var soundObj [3]string
|
||||||
|
soundObj[0] = f.Name()
|
||||||
|
soundObj[1] = base64.StdEncoding.EncodeToString([]byte(f.Name()))
|
||||||
|
soundObj[2] = r.URL.Host + "/v1/play?file=" + soundObj[1]
|
||||||
|
temp = append(temp, soundObj)
|
||||||
|
}
|
||||||
|
// Convert the array to a JSON object and return it to the user
|
||||||
|
j, err := json.Marshal(temp)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Println(string(j))
|
||||||
|
fmt.Fprintf(w, string(j))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user