d19e0ea7a8
MasterBus: stereo master fader, mute, level meters in PiPedal theme (purple accent per mixer-engine branch reference). BusStrip: added per-channel routing selector (ch1Route..ch8Route) for selecting output bus target (Main, Bus 2-8). MixerPage: integrated MasterBus with levels derived from bus master data. Local state for volume/mute until backend exposes master output.
129 lines
4.4 KiB
C++
129 lines
4.4 KiB
C++
// Copyright (c) 2026 Ourpad Network
|
|
// See LICENSE file in the project root for full license text.
|
|
//
|
|
// MixerIpcServer — Unix domain socket IPC server for the OPLabs Mixer Daemon.
|
|
//
|
|
// Protocol:
|
|
// - Transport: Unix domain socket (AF_UNIX, SOCK_STREAM)
|
|
// - Socket path: /tmp/oplabs-mixer.sock
|
|
// - Framing: 4-byte big-endian length prefix (uint32_t) + JSON payload (UTF-8)
|
|
//
|
|
// Request: {"id": <int>, "method": <string>, "params": {<object>}}
|
|
// Response: {"id": <int>, "result": <any>, "error": <string|null>}
|
|
// Push: {"type": "push", "event": <string>, "data": {<object>}}
|
|
//
|
|
// Methods:
|
|
// getState params: {} result: {full mixer state}
|
|
// setChannelVolume params: {channelIndex, volumeDb} result: {}
|
|
// setChannelPan params: {channelIndex, pan} result: {}
|
|
// setChannelMute params: {channelIndex, mute} result: {}
|
|
// setChannelSolo params: {channelIndex, solo} result: {}
|
|
// addChannel params: {physicalInputIndex} result: {channelIndex}
|
|
// removeChannel params: {channelIndex} result: {}
|
|
// getOutputRoutes params: {} result: {routes: [...]}
|
|
// setOutputRoutes params: {routes: [...]} result: {}
|
|
// saveScene params: {name} result: {id, name}
|
|
// loadScene params: {sceneId} result: {ok: bool}
|
|
// listScenes params: {} result: {scenes: [...]}
|
|
// deleteScene params: {sceneId} result: {ok: bool}
|
|
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <functional>
|
|
#include <atomic>
|
|
#include <thread>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
namespace pipedal {
|
|
|
|
class MixerApi;
|
|
class MixerEngine;
|
|
|
|
/// Unix domain socket IPC server that dispatches JSON messages to MixerApi.
|
|
class MixerIpcServer {
|
|
public:
|
|
/// Callback signature: clientConnected, clientDisconnected
|
|
using ConnectionCallback = std::function<void()>;
|
|
using MessageCallback = std::function<void(const std::string&)>;
|
|
|
|
MixerIpcServer();
|
|
~MixerIpcServer();
|
|
|
|
// Disable copy
|
|
MixerIpcServer(const MixerIpcServer&) = delete;
|
|
MixerIpcServer& operator=(const MixerIpcServer&) = delete;
|
|
|
|
/// Set the MixerApi instance to dispatch to.
|
|
void setMixerApi(MixerApi* api) { mixerApi_ = api; }
|
|
|
|
/// Set the MixerEngine instance directly (for push messages / VU).
|
|
void setMixerEngine(MixerEngine* engine) { mixerEngine_ = engine; }
|
|
|
|
/// Start the IPC server on the given socket path.
|
|
/// Returns true on success.
|
|
bool start(const std::string& socketPath = "/tmp/oplabs-mixer.sock");
|
|
|
|
/// Stop the IPC server and close all connections.
|
|
void stop();
|
|
|
|
/// Check if the server is running.
|
|
bool isRunning() const { return running_.load(); }
|
|
|
|
/// Broadcast a push message to all connected clients.
|
|
void broadcast(const std::string& jsonMessage);
|
|
|
|
/// Set callback for incoming messages (for logging/monitoring).
|
|
void setMessageCallback(MessageCallback cb) { messageCallback_ = std::move(cb); }
|
|
|
|
private:
|
|
MixerApi* mixerApi_ = nullptr;
|
|
MixerEngine* mixerEngine_ = nullptr;
|
|
|
|
std::atomic<bool> running_{false};
|
|
int serverFd_ = -1;
|
|
std::string socketPath_;
|
|
std::thread acceptThread_;
|
|
|
|
// Per-client state
|
|
struct ClientConnection {
|
|
int fd = -1;
|
|
bool active = false;
|
|
std::vector<uint8_t> readBuffer;
|
|
uint32_t expectedLength = 0;
|
|
bool readingHeader = true;
|
|
};
|
|
|
|
std::map<int, std::unique_ptr<ClientConnection>> clients_;
|
|
int nextClientId_ = 1;
|
|
|
|
MessageCallback messageCallback_;
|
|
|
|
// Accept loop (runs in its own thread)
|
|
void acceptLoop();
|
|
|
|
// Handle a single client connection
|
|
void handleClient(int clientFd);
|
|
|
|
// Read and accumulate data from a client
|
|
bool readFromClient(ClientConnection& conn);
|
|
|
|
// Process a complete JSON message
|
|
void processMessage(ClientConnection& conn, const std::string& jsonMessage);
|
|
|
|
// Send a JSON response to a specific client
|
|
bool sendResponse(int clientFd, const std::string& jsonResponse);
|
|
|
|
// Convenience: send a length-prefixed frame
|
|
bool sendFrame(int fd, const std::string& jsonPayload);
|
|
|
|
// Dispatch a method call to MixerApi and return JSON result
|
|
std::string dispatchMethod(const std::string& method, const std::string& paramsJson);
|
|
|
|
// All connected client file descriptors
|
|
std::vector<int> connectedClientFds() const;
|
|
};
|
|
|
|
} // namespace pipedal
|