Skip to content

Commit

Permalink
display if in audio mode
Browse files Browse the repository at this point in the history
  • Loading branch information
gferraro committed Aug 12, 2024
1 parent 8a2d4a1 commit bb81f98
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 71 deletions.
8 changes: 5 additions & 3 deletions api/audiorecording.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,18 @@ func (api *ManagementAPI) AudioRecordingStatus(w http.ResponseWriter, r *http.Re
return
}

var result int
err = tc2AgentDbus.Call("org.cacophony.TC2Agent.audiostatus", 0).Store(&result)
var status int
var mode int
err = tc2AgentDbus.Call("org.cacophony.TC2Agent.audiostatus", 0).Store(&mode, &status)
if err != nil {
log.Println(err)
http.Error(w, "Failed to request test audio recoding", http.StatusInternalServerError)
return
}
rp2040status := map[string]int{"mode": mode, "status": status}

w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(result)
json.NewEncoder(w).Encode(rp2040status)

}

Expand Down
110 changes: 67 additions & 43 deletions cmd/managementd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ const (
)

var (
haveClients = make(chan bool)
version = "<not set>"
sockets = make(map[int64]*WebsocketRegistration)
socketsLock sync.RWMutex
headerInfo *headers.HeaderInfo
frameCh = make(chan *FrameData, 4)
currentFrame = -1
haveClients = make(chan bool)
version = "<not set>"
sockets = make(map[int64]*WebsocketRegistration)
socketsLock sync.RWMutex
headerInfo *headers.HeaderInfo
frameCh = make(chan *FrameData, 4)
connected atomic.Bool
)

// Set up and handle page requests.
Expand Down Expand Up @@ -233,7 +233,10 @@ func main() {
listener.Close()

err = handleConn(conn)
frameCh <- &FrameData{Disconnected: true}
log.Printf("camera connection ended with: %v", err)
connected.Store(false)

}
}()

Expand Down Expand Up @@ -262,7 +265,7 @@ func handleConn(conn net.Conn) error {
var frame *cptvframe.Frame = cptvframe.NewFrame(headerInfo)
var frames int = 0
var lastFrame *FrameData

connected.Store(true)
for {
_, err := io.ReadFull(reader, rawFrame)
if err != nil {
Expand Down Expand Up @@ -333,6 +336,10 @@ func WebsocketServer(ws *websocket.Conn) {
LastHeartbeatAt: time.Now(),
AtomicLock: 0,
}
if !connected.Load() {
_ = websocket.Message.Send(ws, "disconnected")
}

socketsLock.Unlock()
if firstSocket {
log.Print("Get new client register")
Expand Down Expand Up @@ -369,40 +376,56 @@ func sendFrameToSockets() {
lastFrame = <-frameCh

if len(sockets) != 0 {
// Make the frame info
buffer := bytes.NewBuffer(make([]byte, 0))
frameInfo := FrameInfo{
Camera: map[string]interface{}{"ResX": headerInfo.ResX(), "ResY": headerInfo.ResY()},
Telemetry: lastFrame.Frame.Status,
Tracks: lastFrame.Tracks,
}
frameInfoJson, _ := json.Marshal(frameInfo)
frameInfoLen := len(frameInfoJson)
// Write out the length of the frameInfo json as a u16
_ = binary.Write(buffer, binary.LittleEndian, uint16(frameInfoLen))
_ = binary.Write(buffer, binary.LittleEndian, frameInfoJson)
for _, row := range lastFrame.Frame.Pix {
_ = binary.Write(buffer, binary.LittleEndian, row)
}
// Send the buffer back to the client
frameBytes := buffer.Bytes()
socketsLock.RLock()
for uuid, socket := range sockets {
go func(socket *WebsocketRegistration, uuid int64, frameNum int) {
// If the socket is busy sending the previous frame,
// don't block, just move on to the next socket.
if atomic.CompareAndSwapUint32(&socket.AtomicLock, 0, 1) {
_ = websocket.Message.Send(socket.Socket, frameBytes)
atomic.StoreUint32(&socket.AtomicLock, 0)
} else {
// Locked, skip this frame to let client catch up.
log.Println("Skipping frame for", uuid, frameNum)
}
}(socket, uuid, frameNum)
if lastFrame.Disconnected {
socketsLock.RLock()
for uuid, socket := range sockets {
go func(socket *WebsocketRegistration, uuid int64, frameNum int) {
// If the socket is busy sending the previous frame,
// don't block, just move on to the next socket.
if atomic.CompareAndSwapUint32(&socket.AtomicLock, 0, 1) {
_ = websocket.Message.Send(socket.Socket, "disconnected")
atomic.StoreUint32(&socket.AtomicLock, 0)
} else {
time.Sleep(100 * time.Millisecond)
}
}(socket, uuid, frameNum)
}
socketsLock.RUnlock()
} else {
// Make the frame info
buffer := bytes.NewBuffer(make([]byte, 0))
frameInfo := FrameInfo{
Camera: map[string]interface{}{"ResX": headerInfo.ResX(), "ResY": headerInfo.ResY()},
Telemetry: lastFrame.Frame.Status,
Tracks: lastFrame.Tracks,
}
frameInfoJson, _ := json.Marshal(frameInfo)
frameInfoLen := len(frameInfoJson)
// Write out the length of the frameInfo json as a u16
_ = binary.Write(buffer, binary.LittleEndian, uint16(frameInfoLen))
_ = binary.Write(buffer, binary.LittleEndian, frameInfoJson)
for _, row := range lastFrame.Frame.Pix {
_ = binary.Write(buffer, binary.LittleEndian, row)
}
// Send the buffer back to the client
frameBytes := buffer.Bytes()
socketsLock.RLock()
for uuid, socket := range sockets {
go func(socket *WebsocketRegistration, uuid int64, frameNum int) {
// If the socket is busy sending the previous frame,
// don't block, just move on to the next socket.
if atomic.CompareAndSwapUint32(&socket.AtomicLock, 0, 1) {
_ = websocket.Message.Send(socket.Socket, frameBytes)
atomic.StoreUint32(&socket.AtomicLock, 0)
} else {
// Locked, skip this frame to let client catch up.
log.Println("Skipping frame for", uuid, frameNum)
}
}(socket, uuid, frameNum)
}
socketsLock.RUnlock()
frameNum = lastFrame.Frame.Status.FrameCount
}
socketsLock.RUnlock()
frameNum = lastFrame.Frame.Status.FrameCount

var socketsToRemove []int64
socketsLock.RLock()
for uuid, socket := range sockets {
Expand Down Expand Up @@ -432,6 +455,7 @@ func sendFrameToSockets() {
}

type FrameData struct {
Frame *cptvframe.Frame
Tracks []map[string]interface{}
Disconnected bool
Frame *cptvframe.Frame
Tracks []map[string]interface{}
}
56 changes: 33 additions & 23 deletions static/js/about.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ async function readAutoUpdate() {
var res = await fetch("/api/auto-update", { headers: authHeaders });
if (res.ok) {
resJson = await res.json();
document.getElementById('auto-update-checkbox').checked = resJson.autoUpdate;
document.getElementById("auto-update-checkbox").checked =
resJson.autoUpdate;
}
}

Expand Down Expand Up @@ -122,15 +123,20 @@ async function updateSaltState() {
var data = JSON.parse(await response.text());

if (data.RunningUpdate) {
document.getElementById("salt-update-button").setAttribute("disabled", true);
document.getElementById("salt-update-button").textContent = "Running Salt Update...";
document
.getElementById("salt-update-button")
.setAttribute("disabled", true);
document.getElementById("salt-update-button").textContent =
"Running Salt Update...";
setTimeout(updateSaltState, 2000);
} else {
enableSaltButton();
}

document.getElementById("salt-update-progress").textContent = data.UpdateProgressPercentage;
document.getElementById("salt-update-progress-text").textContent = data.UpdateProgressStr;
document.getElementById("salt-update-progress").textContent =
data.UpdateProgressPercentage;
document.getElementById("salt-update-progress-text").textContent =
data.UpdateProgressStr;
document.getElementById("running-salt-command").textContent =
data.RunningUpdate ? "Yes" : "No";
document.getElementById("running-salt-arguements").textContent =
Expand All @@ -156,7 +162,8 @@ async function updateSaltState() {

function enableSaltButton() {
document.getElementById("salt-update-button").removeAttribute("disabled");
document.getElementById("salt-update-button").textContent = "Run Salt Update...";
document.getElementById("salt-update-button").textContent =
"Run Salt Update...";
}

var runningSaltUpdate = true;
Expand Down Expand Up @@ -202,37 +209,40 @@ function pollSaltUpdateState() {
}

function getEnvironmentState() {
fetch('/api/salt-grains', {
headers: authHeaders
fetch("/api/salt-grains", {
headers: authHeaders,
})
.then(response => response.json())
.then(data => {
.then((response) => response.json())
.then((data) => {
if (data.environment) {
document.getElementById('environment-select').value = data.environment;
document.getElementById("environment-select").value = data.environment;
}
})
.catch(error => console.error('Error fetching environment state:', error));
})
.catch((error) =>
console.error("Error fetching environment state:", error)
);
}

async function setEnvironment() {
$("#set-environment-button").attr("disabled", true);
$("#set-environment-button").html("Setting Environment");
const selectedEnvironment = document.getElementById('environment-select').value;
const selectedEnvironment =
document.getElementById("environment-select").value;
headers = authHeaders;
headers.append('Content-Type', 'application/json');
headers.append("Content-Type", "application/json");
try {
var response = await fetch('/api/salt-grains', {
method: 'POST',
headers: headers,
body: JSON.stringify({ environment: selectedEnvironment })
})
var response = await fetch("/api/salt-grains", {
method: "POST",
headers: headers,
body: JSON.stringify({ environment: selectedEnvironment }),
});
if (response.ok) {
alert('Environment set successfully');
alert("Environment set successfully");
} else {
alert('Failed to set environment');
alert("Failed to set environment");
}
} catch (error) {
console.error('Error setting environment:', error);
console.error("Error setting environment:", error);
}
$("#set-environment-button").attr("disabled", false);
$("#set-environment-button").html("Set Environment");
Expand Down
9 changes: 7 additions & 2 deletions static/js/audiorecording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ let lastState: number | null = null;
let countdown = 0;
async function getAudioStatus() {
var xmlHttp = new XMLHttpRequest();
xmlHttp.responseType = "json";
xmlHttp.open("GET", "/api/audio/audio-status", true);
xmlHttp.setRequestHeader("Authorization", "Basic " + btoa("admin:feathers"));
var success = false;
xmlHttp.onload = async function () {
if (xmlHttp.status == 200) {
const state = Number(xmlHttp.response);
const rp2040state = xmlHttp.response;
const state = Number(rp2040state.status);
const mode = Number(rp2040state.mode);

let statusText = "";
if (state == 1) {
countdown = 2;
Expand Down Expand Up @@ -52,7 +56,8 @@ async function getAudioStatus() {
}
} else if (state == 4) {
countdown = 2;
statusText = "Already Taking a Recording";
let recType = mode == 1 ? "an audio" : "a thermal";
statusText = `Already Taking ${recType} Recording`;
if (lastState != 4) {
clearInterval(intervalId as number);
document
Expand Down
Loading

0 comments on commit bb81f98

Please sign in to comment.