2024-08-08 13:12:37 -07:00
|
|
|
#pragma once
|
|
|
|
#include <any>
|
|
|
|
#include <mutex>
|
|
|
|
#include <atomic>
|
|
|
|
#include <stdint.h>
|
2024-09-16 15:05:53 -07:00
|
|
|
#include <future>
|
2024-08-08 13:12:37 -07:00
|
|
|
#include <thread>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2024-09-16 15:05:53 -07:00
|
|
|
#include <memory>
|
2024-08-08 13:12:37 -07:00
|
|
|
#include "thirdparty/CRC.hpp"
|
|
|
|
#include "playback_backend.hpp"
|
|
|
|
#include <grpc/grpc.h>
|
|
|
|
#include <grpcpp/security/server_credentials.h>
|
|
|
|
#include <grpcpp/server.h>
|
|
|
|
#include <grpcpp/server_builder.h>
|
|
|
|
#include <grpcpp/server_context.h>
|
|
|
|
#include "rpc.hpp"
|
|
|
|
#include "ipc/common.pb.h"
|
|
|
|
#include "ipc/internal.pb.h"
|
|
|
|
#include "ipc/internal.grpc.pb.h"
|
|
|
|
#include <log.hpp>
|
|
|
|
class PlaybackProcess;
|
|
|
|
class PlaybackProcessServiceImpl : public PlaybackProcessService::Service {
|
|
|
|
PlaybackBackend *cur_backend;
|
|
|
|
public:
|
|
|
|
PlaybackProcess *process;
|
|
|
|
grpc::Status Init(grpc::ServerContext *ctx, const InitCommand *cmd, MaybeError *response) override;
|
|
|
|
grpc::Status Render(grpc::ServerContext *context, const RenderCommand *cmd, RenderResponseOrError *response) override;
|
|
|
|
grpc::Status Get(grpc::ServerContext *ctx, const GetProperty *request, PropertyDataOrError *response) override;
|
|
|
|
grpc::Status Set(grpc::ServerContext *ctx, const SetProperty *request, MaybeError *err) override;
|
|
|
|
grpc::Status Reset(grpc::ServerContext *ctx, const ResetProperty *request, ResetResponse *response) override;
|
|
|
|
grpc::Status Quit(grpc::ServerContext *ctx, const QuitCmd *request, MaybeError *response) override;
|
|
|
|
};
|
|
|
|
class HostProcessImpl : public HostProcess::Service {
|
|
|
|
public:
|
|
|
|
PlaybackProcess *process;
|
|
|
|
grpc::Status WriteLog(grpc::ServerContext *ctx, const LogMessage *msg, SimpleAckResponse *response) override;
|
|
|
|
grpc::Status SetAddress(grpc::ServerContext *ctx, const StringProperty *data, MaybeError *response) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
inline T *resolve_any(google::protobuf::Any value) {
|
|
|
|
T *output = new T();
|
|
|
|
value.UnpackTo(output);
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
//#define DEBUG_PRINT_IPC
|
|
|
|
void print_ipc_message(const google::protobuf::Message &msg, size_t level = 0);
|
|
|
|
class PlaybackProcess {
|
|
|
|
friend class HostProcessImpl;
|
|
|
|
friend class PlaybackProcessServiceImpl;
|
|
|
|
void threadfunc();
|
|
|
|
int pid;
|
2024-09-16 15:05:53 -07:00
|
|
|
std::mutex start_mutex;
|
|
|
|
std::condition_variable started;
|
2024-08-08 13:12:37 -07:00
|
|
|
bool is_playback_process = false;
|
2024-09-16 15:05:53 -07:00
|
|
|
std::atomic_bool done;
|
2024-08-08 13:12:37 -07:00
|
|
|
std::optional<IPCChannel<HostProcess, PlaybackProcessService>> host_channel;
|
|
|
|
std::optional<IPCChannel<PlaybackProcessService, HostProcess>> playback_process_channel;
|
|
|
|
inline std::unique_ptr<PlaybackProcessService::Stub> get_stub() {
|
|
|
|
return host_channel.value().get_stub();
|
|
|
|
}
|
|
|
|
std::string get_version_code();
|
|
|
|
PropertyData get_property(PropertyId id, std::optional<uint64_t> idx = {});
|
|
|
|
inline google::protobuf::Any get_property_value_any(PropertyId id, std::optional<uint64_t> idx = {}) {
|
|
|
|
PropertyData data = get_property(id, idx);
|
|
|
|
return data.value();
|
|
|
|
}
|
|
|
|
template<class T>
|
|
|
|
inline T *get_property_value(PropertyId id, std::optional<uint64_t> idx = {}) {
|
|
|
|
if constexpr (std::is_same_v<T, std::string>) {
|
|
|
|
auto *property = get_property_value<StringProperty>(id, idx);
|
|
|
|
std::string *tmp = new std::string(property->value());
|
|
|
|
delete property;
|
|
|
|
return tmp;
|
|
|
|
} else {
|
|
|
|
return resolve_any<T>(get_property_value_any(id, idx));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inline std::string get_property_string(PropertyId id, std::optional<uint64_t> idx = {}) {
|
|
|
|
auto *property = get_property_value<StringProperty>(id, idx);
|
|
|
|
std::string output = std::string(property->value());
|
|
|
|
delete property;
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
void set_property(PropertyId id, PropertyData data, std::optional<uint64_t> idx = {});
|
|
|
|
template<class T>
|
|
|
|
inline void set_property_value(PropertyId id, T *value, std::optional<uint64_t> idx = {}) {
|
|
|
|
PropertyData data;
|
|
|
|
data.mutable_value()->PackFrom(*value);
|
|
|
|
set_property(id, data, idx);
|
|
|
|
}
|
|
|
|
friend int looper_run_playback_process(std::vector<std::string> args);
|
|
|
|
PlaybackProcess(std::vector<std::string> args);
|
|
|
|
void run_playback_process();
|
|
|
|
public:
|
|
|
|
bool process_running();
|
|
|
|
double get_position();
|
|
|
|
void set_position(double pos);
|
|
|
|
size_t get_stream_idx();
|
|
|
|
void set_stream_idx(size_t idx);
|
|
|
|
std::string get_title();
|
|
|
|
std::string get_file_path();
|
|
|
|
std::string get_file_name();
|
|
|
|
std::string get_backend_id();
|
|
|
|
std::string get_backend_name();
|
|
|
|
PlaybackStream get_playback_stream(size_t idx);
|
|
|
|
std::vector<PlaybackStream> get_playback_streams();
|
|
|
|
AudioSpec *get_audio_spec();
|
|
|
|
size_t render(void *buf, size_t maxlen);
|
|
|
|
|
|
|
|
std::optional<google::protobuf::Any> get_property(std::string path);
|
|
|
|
bool set_property(std::string path, google::protobuf::Any value);
|
|
|
|
PlaybackProcess(std::string filename, int idx = 0);
|
|
|
|
~PlaybackProcess();
|
|
|
|
};
|