@@ -1881,6 +1881,7 @@ class CarlaHostNull(CarlaHostMeta): | |||
CarlaHostMeta.__init__(self) | |||
self.fEngineCallback = None | |||
self.fFileCallback = None | |||
self.fEngineRunning = False | |||
def get_engine_driver_count(self): | |||
@@ -1923,7 +1924,7 @@ class CarlaHostNull(CarlaHostMeta): | |||
return | |||
def set_file_callback(self, func): | |||
return | |||
self.fFileCallback = func | |||
def load_file(self, filename): | |||
return False | |||
@@ -26,6 +26,52 @@ import requests | |||
from carla_backend_qt import * | |||
import os | |||
from time import sleep | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Iterates over the content of a file-like object line-by-line. | |||
# Based on code by Lars Kellogg-Stedman, see https://github.com/requests/requests/issues/2433 | |||
def iterate_stream_nonblock(stream, chunk_size=128): | |||
pending = None | |||
while True: | |||
try: | |||
chunk = os.read(stream.raw.fileno(), chunk_size) | |||
except BlockingIOError: | |||
break | |||
if not chunk: | |||
break | |||
if pending is not None: | |||
chunk = pending + chunk | |||
pending = None | |||
lines = chunk.splitlines() | |||
if lines and lines[-1]: | |||
pending = lines.pop() | |||
for line in lines: | |||
yield line | |||
if not pending: | |||
break | |||
if pending: | |||
yield pending | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
def create_stream(baseurl): | |||
stream = requests.get("{}/stream".format(baseurl), stream=True, timeout=0.1) | |||
if stream.encoding is None: | |||
stream.encoding = 'utf-8' | |||
return stream | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Carla Host object for connecting to the REST API | |||
@@ -34,6 +80,7 @@ class CarlaHostQtWeb(CarlaHostQtNull): | |||
CarlaHostQtNull.__init__(self) | |||
self.baseurl = "http://localhost:2228" | |||
self.stream = create_stream(self.baseurl) | |||
def get_engine_driver_count(self): | |||
# FIXME | |||
@@ -49,33 +96,277 @@ class CarlaHostQtWeb(CarlaHostQtNull): | |||
return requests.get("{}/get_engine_driver_device_info/{}/{}".format(self.baseurl, index, name)).json() | |||
def engine_init(self, driverName, clientName): | |||
resp = requests.get("{}/engine_init/{}/{}".format(self.baseurl, driverName, clientName)).status_code | |||
# TESTING | |||
if self.fEngineCallback is not None: | |||
self.fEngineCallback(None, ENGINE_CALLBACK_ENGINE_STARTED, 0, self.processMode, self.transportMode, 0.0, driverName) | |||
return resp == 200 | |||
return requests.get("{}/engine_init/{}/{}".format(self.baseurl, driverName, clientName)).status_code == 200 | |||
def engine_close(self): | |||
# TESTING | |||
if self.fEngineCallback is not None: | |||
self.fEngineCallback(None, ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0.0, "") | |||
return requests.get("{}/engine_close".format(self.baseurl)).status_code == 200 | |||
def engine_idle(self): | |||
requests.get("{}/engine_idle".format(self.baseurl)) | |||
closed = False | |||
stream = self.stream | |||
for line in iterate_stream_nonblock(stream): | |||
line = line.decode('utf-8', errors='ignore') | |||
if line.startswith("Carla: "): | |||
if self.fEngineCallback is None: | |||
continue | |||
# split values from line | |||
action, pluginId, value1, value2, value3, valueStr = line[7:].split(" ",5) | |||
# convert to proper types | |||
action = int(action) | |||
pluginId = int(pluginId) | |||
value1 = int(value1) | |||
value2 = int(value2) | |||
value3 = float(value3) | |||
# pass to callback | |||
self.fEngineCallback(None, action, pluginId, value1, value2, value3, valueStr) | |||
elif line == "Connection: close": | |||
closed = True | |||
if closed: | |||
self.stream = create_stream(self.baseurl) | |||
stream.close() | |||
def is_engine_running(self): | |||
return requests.get("{}/is_engine_running".format(self.baseurl)).status_code == 200 | |||
try: | |||
return requests.get("{}/is_engine_running".format(self.baseurl)).status_code == 200 | |||
except requests.exceptions.ConnectionError: | |||
if self.fEngineCallback is None: | |||
self.fEngineCallback(None, ENGINE_CALLBACK_QUIT, 0, 0, 0, 0.0, "") | |||
def set_engine_about_to_close(self): | |||
return requests.get("{}/set_engine_about_to_close".format(self.baseurl)).status_code == 200 | |||
def set_engine_option(self, option, value, valueStr): | |||
return | |||
def load_file(self, filename): | |||
return False | |||
def load_project(self, filename): | |||
return False | |||
def save_project(self, filename): | |||
return False | |||
def patchbay_connect(self, groupIdA, portIdA, groupIdB, portIdB): | |||
return False | |||
def patchbay_disconnect(self, connectionId): | |||
return False | |||
def patchbay_refresh(self, external): | |||
return False | |||
def transport_play(self): | |||
return | |||
def transport_pause(self): | |||
return | |||
def transport_bpm(self, bpm): | |||
return | |||
def transport_relocate(self, frame): | |||
return | |||
def get_current_transport_frame(self): | |||
return 0 | |||
def get_transport_info(self): | |||
return PyCarlaTransportInfo | |||
def get_current_plugin_count(self): | |||
return 0 | |||
def get_max_plugin_number(self): | |||
return 0 | |||
def add_plugin(self, btype, ptype, filename, name, label, uniqueId, extraPtr, options): | |||
return False | |||
def remove_plugin(self, pluginId): | |||
return False | |||
def remove_all_plugins(self): | |||
return False | |||
def rename_plugin(self, pluginId, newName): | |||
return "" | |||
def clone_plugin(self, pluginId): | |||
return False | |||
def replace_plugin(self, pluginId): | |||
return False | |||
def switch_plugins(self, pluginIdA, pluginIdB): | |||
return False | |||
def load_plugin_state(self, pluginId, filename): | |||
return False | |||
def save_plugin_state(self, pluginId, filename): | |||
return False | |||
def export_plugin_lv2(self, pluginId, lv2path): | |||
return False | |||
def get_plugin_info(self, pluginId): | |||
return PyCarlaPluginInfo | |||
def get_audio_port_count_info(self, pluginId): | |||
return PyCarlaPortCountInfo | |||
def get_midi_port_count_info(self, pluginId): | |||
return PyCarlaPortCountInfo | |||
def get_parameter_count_info(self, pluginId): | |||
return PyCarlaPortCountInfo | |||
def get_parameter_info(self, pluginId, parameterId): | |||
return PyCarlaParameterInfo | |||
def get_parameter_scalepoint_info(self, pluginId, parameterId, scalePointId): | |||
return PyCarlaScalePointInfo | |||
def get_parameter_data(self, pluginId, parameterId): | |||
return PyParameterData | |||
def get_parameter_ranges(self, pluginId, parameterId): | |||
return PyParameterRanges | |||
def get_midi_program_data(self, pluginId, midiProgramId): | |||
return PyMidiProgramData | |||
def get_custom_data(self, pluginId, customDataId): | |||
return PyCustomData | |||
def get_chunk_data(self, pluginId): | |||
return "" | |||
def get_parameter_count(self, pluginId): | |||
return 0 | |||
def get_program_count(self, pluginId): | |||
return 0 | |||
def get_midi_program_count(self, pluginId): | |||
return 0 | |||
def get_custom_data_count(self, pluginId): | |||
return 0 | |||
def get_parameter_text(self, pluginId, parameterId): | |||
return "" | |||
def get_program_name(self, pluginId, programId): | |||
return "" | |||
def get_midi_program_name(self, pluginId, midiProgramId): | |||
return "" | |||
def get_real_plugin_name(self, pluginId): | |||
return "" | |||
def get_current_program_index(self, pluginId): | |||
return 0 | |||
def get_current_midi_program_index(self, pluginId): | |||
return 0 | |||
def get_default_parameter_value(self, pluginId, parameterId): | |||
return 0.0 | |||
def get_current_parameter_value(self, pluginId, parameterId): | |||
return 0.0 | |||
def get_internal_parameter_value(self, pluginId, parameterId): | |||
return 0.0 | |||
def get_input_peak_value(self, pluginId, isLeft): | |||
return 0.0 | |||
def get_output_peak_value(self, pluginId, isLeft): | |||
return 0.0 | |||
def set_option(self, pluginId, option, yesNo): | |||
return | |||
def set_active(self, pluginId, onOff): | |||
return | |||
def set_drywet(self, pluginId, value): | |||
return | |||
def set_volume(self, pluginId, value): | |||
return | |||
def set_balance_left(self, pluginId, value): | |||
return | |||
def set_balance_right(self, pluginId, value): | |||
return | |||
def set_panning(self, pluginId, value): | |||
return | |||
def set_ctrl_channel(self, pluginId, channel): | |||
return | |||
def set_parameter_value(self, pluginId, parameterId, value): | |||
return | |||
def set_parameter_midi_channel(self, pluginId, parameterId, channel): | |||
return | |||
def set_parameter_midi_cc(self, pluginId, parameterId, cc): | |||
return | |||
def set_program(self, pluginId, programId): | |||
return | |||
def set_midi_program(self, pluginId, midiProgramId): | |||
return | |||
def set_custom_data(self, pluginId, type_, key, value): | |||
return | |||
def set_chunk_data(self, pluginId, chunkData): | |||
return | |||
def prepare_for_save(self, pluginId): | |||
return | |||
def reset_parameters(self, pluginId): | |||
return | |||
def randomize_parameters(self, pluginId): | |||
return | |||
def send_midi_note(self, pluginId, channel, note, velocity): | |||
return | |||
def get_buffer_size(self): | |||
return 0 | |||
def get_sample_rate(self): | |||
return 0.0 | |||
def get_last_error(self): | |||
return requests.get("{}/get_last_error".format(self.baseurl)).text | |||
def get_host_osc_url_tcp(self): | |||
return "" | |||
def get_host_osc_url_udp(self): | |||
return "" | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# TESTING | |||
@@ -83,18 +374,36 @@ if __name__ == '__main__': | |||
baseurl = "http://localhost:2228" | |||
driver_count = int(requests.get("{}/get_engine_driver_count".format(baseurl)).text) | |||
#driver_count = int(requests.get("{}/get_engine_driver_count".format(baseurl)).text) | |||
## FIXME | |||
#driver_count -= 1 | |||
#print("Driver names:") | |||
#for index in range(driver_count): | |||
#print("\t -", requests.get("{}/get_engine_driver_name/{}".format(baseurl, index)).text) | |||
#print("Driver device names:") | |||
#for index in range(driver_count): | |||
#for name in requests.get("{}/get_engine_driver_device_names/{}".format(baseurl, index)).text.split("\n"): | |||
#print("\t {}:".format(name), requests.get("{}/get_engine_driver_device_info/{}/{}".format(baseurl, index, name)).json()) | |||
requests.get("{}/engine_close".format(baseurl)).status_code | |||
if requests.get("{}/engine_init/{}/{}".format(baseurl, "JACK", "test")).status_code == 200: | |||
stream = requests.get("{}/stream".format(baseurl), stream=True, timeout=0.25) | |||
#stream.add_done_callback(cb) | |||
#print(stream, dir(stream)) | |||
# FIXME | |||
driver_count -= 1 | |||
#for line in stream.iter_lines(): | |||
#print("line", stream, line) | |||
print("Driver names:") | |||
for index in range(driver_count): | |||
print("\t -", requests.get("{}/get_engine_driver_name/{}".format(baseurl, index)).text) | |||
while True: | |||
print("idle") | |||
for line in iterate_stream_nonblock(stream): | |||
print("line", line) | |||
sleep(0.5) | |||
print("Driver device names:") | |||
for index in range(driver_count): | |||
for name in requests.get("{}/get_engine_driver_device_names/{}".format(baseurl, index)).text.split("\n"): | |||
print("\t {}:".format(name), requests.get("{}/get_engine_driver_device_info/{}/{}".format(baseurl, index, name)).json()) | |||
requests.get("{}/engine_close".format(baseurl)).status_code | |||
# --------------------------------------------------------------------------------------------------------------------- |
@@ -23,7 +23,7 @@ endif | |||
BUILD_CXX_FLAGS += -I$(CWD) -I$(CWD)/backend -I$(CWD)/includes -I$(CWD)/modules -I$(CWD)/utils | |||
LINK_FLAGS += -L$(BINDIR) -lcarla_standalone2 -lcarla_utils -lrestbed -Wl,-rpath=$(shell realpath $(CWD)/../bin) | |||
LINK_FLAGS += -L$(BINDIR) -lcarla_standalone2 -lcarla_utils -lrestbed -lpthread -Wl,-rpath=$(shell realpath $(CWD)/../bin) | |||
# ---------------------------------------------------------------------------------------------------------------------- | |||
@@ -18,6 +18,59 @@ | |||
#include "common.hpp" | |||
#include "CarlaHost.h" | |||
#include "CarlaBackendUtils.hpp" | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
static bool gEngineRunning = false; | |||
void engine_idle_handler() | |||
{ | |||
if (gEngineRunning) | |||
carla_engine_idle(); | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
static void EngineCallback(void* ptr, EngineCallbackOpcode action, uint pluginId, int value1, int value2, float value3, const char* valueStr) | |||
{ | |||
carla_stdout("EngineCallback(%p, %u:%s, %u, %i, %i, %f, %s)", | |||
ptr, (uint)action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valueStr); | |||
char msgBuf[1024]; | |||
std::snprintf(msgBuf, 1023, "Carla: %u %u %i %i %f %s\n", action, pluginId, value1, value2, value3, valueStr); | |||
msgBuf[1023] = '\0'; | |||
switch (action) | |||
{ | |||
case ENGINE_CALLBACK_ENGINE_STARTED: | |||
gEngineRunning = true; | |||
break; | |||
case ENGINE_CALLBACK_ENGINE_STOPPED: | |||
case ENGINE_CALLBACK_QUIT: | |||
gEngineRunning = false; | |||
break; | |||
default: | |||
break; | |||
} | |||
send_server_side_message(msgBuf); | |||
} | |||
static const char* FileCallback(void* ptr, FileCallbackOpcode action, bool isDir, const char* title, const char* filter) | |||
{ | |||
carla_stdout("FileCallback(%p, %u:%s, %s, %s, %s)", | |||
ptr, (uint)action, FileCallbackOpcode(action), bool2str(isDir), title, filter); | |||
char msgBuf[1024]; | |||
std::snprintf(msgBuf, 1023, "fc %u %i \"%s\" \"%s\"", action, isDir, title, filter); | |||
msgBuf[1023] = '\0'; | |||
send_server_side_message(msgBuf); | |||
// FIXME, need to wait for response! | |||
return nullptr; | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
@@ -74,6 +127,11 @@ void handle_carla_get_engine_driver_device_info(const std::shared_ptr<Session> s | |||
void handle_carla_engine_init(const std::shared_ptr<Session> session) | |||
{ | |||
// setup callbacks | |||
carla_set_engine_callback(EngineCallback, nullptr); | |||
carla_set_file_callback(FileCallback, nullptr); | |||
// handle request now | |||
const std::shared_ptr<const Request> request = session->get_request(); | |||
const std::string driverName = request->get_path_parameter("driverName"); | |||
@@ -89,12 +147,6 @@ void handle_carla_engine_close(const std::shared_ptr<Session> session) | |||
session->close(resp ? OK : BAD_REQUEST); | |||
} | |||
void handle_carla_engine_idle(const std::shared_ptr<Session> session) | |||
{ | |||
carla_engine_idle(); | |||
session->close(OK); | |||
} | |||
void handle_carla_is_engine_running(const std::shared_ptr<Session> session) | |||
{ | |||
const bool resp = carla_is_engine_running(); | |||
@@ -109,10 +161,124 @@ void handle_carla_set_engine_about_to_close(const std::shared_ptr<Session> sessi | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT void carla_set_engine_option(EngineOption option, int value, const char* valueStr); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT bool carla_load_file(const char* filename); | |||
CARLA_EXPORT bool carla_load_project(const char* filename); | |||
CARLA_EXPORT bool carla_save_project(const char* filename); | |||
CARLA_EXPORT bool carla_patchbay_connect(uint groupIdA, uint portIdA, uint groupIdB, uint portIdB); | |||
CARLA_EXPORT bool carla_patchbay_disconnect(uint connectionId); | |||
CARLA_EXPORT bool carla_patchbay_refresh(bool external); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT void carla_transport_play(); | |||
CARLA_EXPORT void carla_transport_pause(); | |||
CARLA_EXPORT void carla_transport_bpm(double bpm); | |||
CARLA_EXPORT void carla_transport_relocate(uint64_t frame); | |||
CARLA_EXPORT uint64_t carla_get_current_transport_frame(); | |||
CARLA_EXPORT const CarlaTransportInfo* carla_get_transport_info(); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT uint32_t carla_get_current_plugin_count(); | |||
CARLA_EXPORT uint32_t carla_get_max_plugin_number(); | |||
CARLA_EXPORT bool carla_add_plugin(BinaryType btype, PluginType ptype, | |||
const char* filename, const char* name, const char* label, int64_t uniqueId, | |||
const void* extraPtr, uint options); | |||
CARLA_EXPORT bool carla_remove_plugin(uint pluginId); | |||
CARLA_EXPORT bool carla_remove_all_plugins(); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT const char* carla_rename_plugin(uint pluginId, const char* newName); | |||
CARLA_EXPORT bool carla_clone_plugin(uint pluginId); | |||
CARLA_EXPORT bool carla_replace_plugin(uint pluginId); | |||
CARLA_EXPORT bool carla_switch_plugins(uint pluginIdA, uint pluginIdB); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT bool carla_load_plugin_state(uint pluginId, const char* filename); | |||
CARLA_EXPORT bool carla_save_plugin_state(uint pluginId, const char* filename); | |||
CARLA_EXPORT bool carla_export_plugin_lv2(uint pluginId, const char* lv2path); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT const CarlaPluginInfo* carla_get_plugin_info(uint pluginId); | |||
CARLA_EXPORT const CarlaPortCountInfo* carla_get_audio_port_count_info(uint pluginId); | |||
CARLA_EXPORT const CarlaPortCountInfo* carla_get_midi_port_count_info(uint pluginId); | |||
CARLA_EXPORT const CarlaPortCountInfo* carla_get_parameter_count_info(uint pluginId); | |||
CARLA_EXPORT const CarlaParameterInfo* carla_get_parameter_info(uint pluginId, uint32_t parameterId); | |||
CARLA_EXPORT const CarlaScalePointInfo* carla_get_parameter_scalepoint_info(uint pluginId, uint32_t parameterId, uint32_t scalePointId); | |||
CARLA_EXPORT const ParameterData* carla_get_parameter_data(uint pluginId, uint32_t parameterId); | |||
CARLA_EXPORT const ParameterRanges* carla_get_parameter_ranges(uint pluginId, uint32_t parameterId); | |||
CARLA_EXPORT const MidiProgramData* carla_get_midi_program_data(uint pluginId, uint32_t midiProgramId); | |||
CARLA_EXPORT const CustomData* carla_get_custom_data(uint pluginId, uint32_t customDataId); | |||
CARLA_EXPORT const char* carla_get_chunk_data(uint pluginId); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT uint32_t carla_get_parameter_count(uint pluginId); | |||
CARLA_EXPORT uint32_t carla_get_program_count(uint pluginId); | |||
CARLA_EXPORT uint32_t carla_get_midi_program_count(uint pluginId); | |||
CARLA_EXPORT uint32_t carla_get_custom_data_count(uint pluginId); | |||
CARLA_EXPORT const char* carla_get_parameter_text(uint pluginId, uint32_t parameterId); | |||
CARLA_EXPORT const char* carla_get_program_name(uint pluginId, uint32_t programId); | |||
CARLA_EXPORT const char* carla_get_midi_program_name(uint pluginId, uint32_t midiProgramId); | |||
CARLA_EXPORT const char* carla_get_real_plugin_name(uint pluginId); | |||
CARLA_EXPORT int32_t carla_get_current_program_index(uint pluginId); | |||
CARLA_EXPORT int32_t carla_get_current_midi_program_index(uint pluginId); | |||
CARLA_EXPORT float carla_get_default_parameter_value(uint pluginId, uint32_t parameterId); | |||
CARLA_EXPORT float carla_get_current_parameter_value(uint pluginId, uint32_t parameterId); | |||
CARLA_EXPORT float carla_get_internal_parameter_value(uint pluginId, int32_t parameterId); | |||
CARLA_EXPORT float carla_get_input_peak_value(uint pluginId, bool isLeft); | |||
CARLA_EXPORT float carla_get_output_peak_value(uint pluginId, bool isLeft); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT void carla_set_active(uint pluginId, bool onOff); | |||
CARLA_EXPORT void carla_set_drywet(uint pluginId, float value); | |||
CARLA_EXPORT void carla_set_volume(uint pluginId, float value); | |||
CARLA_EXPORT void carla_set_balance_left(uint pluginId, float value); | |||
CARLA_EXPORT void carla_set_balance_right(uint pluginId, float value); | |||
CARLA_EXPORT void carla_set_panning(uint pluginId, float value); | |||
CARLA_EXPORT void carla_set_ctrl_channel(uint pluginId, int8_t channel); | |||
CARLA_EXPORT void carla_set_option(uint pluginId, uint option, bool yesNo); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT void carla_set_parameter_value(uint pluginId, uint32_t parameterId, float value); | |||
CARLA_EXPORT void carla_set_parameter_midi_channel(uint pluginId, uint32_t parameterId, uint8_t channel); | |||
CARLA_EXPORT void carla_set_parameter_midi_cc(uint pluginId, uint32_t parameterId, int16_t cc); | |||
CARLA_EXPORT void carla_set_program(uint pluginId, uint32_t programId); | |||
CARLA_EXPORT void carla_set_midi_program(uint pluginId, uint32_t midiProgramId); | |||
CARLA_EXPORT void carla_set_custom_data(uint pluginId, const char* type, const char* key, const char* value); | |||
CARLA_EXPORT void carla_set_chunk_data(uint pluginId, const char* chunkData); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT void carla_prepare_for_save(uint pluginId); | |||
CARLA_EXPORT void carla_reset_parameters(uint pluginId); | |||
CARLA_EXPORT void carla_randomize_parameters(uint pluginId); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT void carla_send_midi_note(uint pluginId, uint8_t channel, uint8_t note, uint8_t velocity); | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT uint32_t carla_get_buffer_size(); | |||
CARLA_EXPORT double carla_get_sample_rate(); | |||
void handle_carla_get_last_error(const std::shared_ptr<Session> session) | |||
{ | |||
const char* const buf = carla_get_last_error(); | |||
session->close(OK, buf, { { "Content-Length", size_buf(buf) } } ); | |||
} | |||
CARLA_EXPORT const char* carla_get_host_osc_url_tcp(); | |||
CARLA_EXPORT const char* carla_get_host_osc_url_udp(); | |||
// ------------------------------------------------------------------------------------------------------------------- |
@@ -35,4 +35,6 @@ using restbed::OK; | |||
CARLA_BACKEND_USE_NAMESPACE; | |||
void send_server_side_message(const char* const message); | |||
#endif // REST_COMMON_HPP_INCLUDED |
@@ -26,9 +26,71 @@ | |||
#include "carla-host.cpp" | |||
#include "carla-utils.cpp" | |||
#include "CarlaMutex.hpp" | |||
#include "CarlaStringList.hpp" | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
std::vector<std::shared_ptr<Session>> gSessions; | |||
CarlaStringList gSessionMessages; | |||
CarlaMutex gSessionMessagesMutex; | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
void send_server_side_message(const char* const message) | |||
{ | |||
const CarlaMutexLocker cml(gSessionMessagesMutex); | |||
gSessionMessages.append(message); | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
void make_resource(Service& service, | |||
static void register_server_side_handler(const std::shared_ptr<Session> session) | |||
{ | |||
const auto headers = std::multimap<std::string, std::string> { | |||
{ "Connection", "keep-alive" }, | |||
{ "Cache-Control", "no-cache" }, | |||
{ "Content-Type", "text/event-stream" }, | |||
{ "Access-Control-Allow-Origin", "*" } //Only required for demo purposes. | |||
}; | |||
session->yield(OK, headers, [](const std::shared_ptr<Session> rsession) { | |||
gSessions.push_back(rsession); | |||
}); | |||
} | |||
static void event_stream_handler(void) | |||
{ | |||
gSessions.erase( | |||
std::remove_if(gSessions.begin(), gSessions.end(), | |||
[](const std::shared_ptr<Session> &a) { | |||
return a->is_closed(); | |||
}), | |||
gSessions.end()); | |||
CarlaStringList messages; | |||
{ | |||
const CarlaMutexLocker cml(gSessionMessagesMutex); | |||
if (gSessionMessages.count() > 0) | |||
gSessionMessages.moveTo(messages); | |||
} | |||
for (auto message : messages) | |||
{ | |||
std::puts(message); | |||
for (auto session : gSessions) | |||
session->yield(OK, message); | |||
} | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
static void make_resource(Service& service, | |||
const char* const path, | |||
const std::function<void (const std::shared_ptr<Session>)>& callback) | |||
{ | |||
@@ -44,6 +106,14 @@ int main(int, const char**) | |||
{ | |||
Service service; | |||
// server-side messages | |||
{ | |||
std::shared_ptr<Resource> resource = std::make_shared<Resource>(); | |||
resource->set_path("/stream"); | |||
resource->set_method_handler("GET", register_server_side_handler); | |||
service.publish(resource); | |||
} | |||
// carla-host | |||
make_resource(service, "/get_engine_driver_count", handle_carla_get_engine_driver_count); | |||
make_resource(service, "/get_engine_driver_name/{index: .*}", handle_carla_get_engine_driver_name); | |||
@@ -52,7 +122,6 @@ int main(int, const char**) | |||
make_resource(service, "/engine_init/{driverName: .*}/{clientName: .*}", handle_carla_engine_init); | |||
make_resource(service, "/engine_close", handle_carla_engine_close); | |||
make_resource(service, "/engine_idle", handle_carla_engine_idle); | |||
make_resource(service, "/is_engine_running", handle_carla_is_engine_running); | |||
make_resource(service, "/set_engine_about_to_close", handle_carla_set_engine_about_to_close); | |||
@@ -66,6 +135,10 @@ int main(int, const char**) | |||
make_resource(service, "/get_cached_plugin_count/{ptype: .*}/{pluginPath: .*}", handle_carla_get_cached_plugin_count); | |||
make_resource(service, "/get_cached_plugin_info/{ptype: .*}/{index: .*}", handle_carla_get_cached_plugin_info); | |||
// schedule events | |||
service.schedule(engine_idle_handler, std::chrono::milliseconds(33)); // ~30Hz | |||
service.schedule(event_stream_handler, std::chrono::milliseconds(500)); | |||
std::shared_ptr<Settings> settings = std::make_shared<Settings>(); | |||
settings->set_port(2228); | |||
settings->set_default_header("Connection", "close"); | |||
@@ -159,6 +159,7 @@ public: | |||
return *this; | |||
} | |||
#if 0 | |||
T& operator*() noexcept | |||
{ | |||
static T& fallback(_getFallback()); | |||
@@ -168,6 +169,7 @@ public: | |||
return data->value; | |||
} | |||
#endif | |||
const T& operator*() const noexcept | |||
{ | |||
@@ -180,8 +182,8 @@ public: | |||
} | |||
private: | |||
ListHead* fEntry; | |||
ListHead* fEntry2; | |||
const ListHead* fEntry; | |||
const ListHead* fEntry2; | |||
static T& _getFallback() | |||
{ | |||