From: Daniel Karbach Date: Wed, 25 Sep 2024 22:12:03 +0000 (+0200) Subject: websockets X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=714b1d1cc1f599b34b275a9c02b4897291a2fabc;p=ffmpeg-test.git websockets --- diff --git a/Makefile b/Makefile index 9554743..d2d0188 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CPP_SRCS = $(shell find src -name \*.cpp) CPP_DEPS = $(shell find src -name \*.h) -LIBS = cairo freetype2 libavformat libavcodec libavutil libswresample libswscale +LIBS = cairo freetype2 jsoncpp libavformat libavcodec libavutil libswresample libswscale libuv libwebsockets main: $(CPP_SRCS) $(CPP_DEPS) clang++ -g $(shell pkg-config --cflags --libs $(LIBS)) $(CPP_SRCS) -o $@ diff --git a/src/app/Renderer.h b/src/app/Renderer.h index 41915a7..d32587f 100644 --- a/src/app/Renderer.h +++ b/src/app/Renderer.h @@ -24,7 +24,8 @@ public: , surface(plane, linesize, CAIRO_FORMAT_ARGB32, width, height) , ctx(surface.CreateContext()) , width(width) - , height(height) { + , height(height) + , text("Hello") { } ~Renderer() { } @@ -41,11 +42,15 @@ public: ctx.SetFontFace(font); ctx.SetFontSize(16); ctx.SetSourceRGB(1, 1, 1); - ctx.ShowText("Hello"); + ctx.ShowText(text.c_str()); surface.Flush(); } + void SetText(const std::string &t) { + text = t; + } + private: freetype::Library ft; @@ -57,6 +62,8 @@ private: int width; int height; + std::string text; + }; } diff --git a/src/cairo/Context.h b/src/cairo/Context.h index a652555..0eaa600 100644 --- a/src/cairo/Context.h +++ b/src/cairo/Context.h @@ -10,6 +10,8 @@ namespace cairo { +using TextExtends = cairo_text_extents_t; + class Context { public: @@ -38,6 +40,10 @@ public: cairo_fill(ctx); } + void GetTextExtends(const char *text, TextExtends &extends) { + cairo_text_extents(ctx, text, &extends); + } + void MoveTo(double x, double y) { cairo_move_to(ctx, x, y); } diff --git a/src/main.cpp b/src/main.cpp index a514c09..33833f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include extern "C" { #include @@ -18,6 +19,9 @@ extern "C" { #include "app/Renderer.h" #include "app/Stream.h" +#include "uv/Loop.h" +#include "ws/Connection.h" +#include "ws/Context.h" namespace { @@ -28,6 +32,15 @@ void stop(int) { running = false; } +void ws_handler(void *user, const Json::Value &json) { + const std::string data_string = json["data"].asString(); + Json::Value data; + Json::Reader json_reader; + json_reader.parse(data_string, data); + app::Renderer *renderer = static_cast(user); + renderer->SetText(data["model"]["text"].asString()); +} + } @@ -37,6 +50,11 @@ int main(int argc, char**argv) { const int FPS = 60; const char *URL = "rtmp://localhost/localhorsttv"; + uv::Loop loop; + + ws::Context wsctx(loop); + ws::Connection wsconn(wsctx.GetContext()); + app::Stream stream(URL, WIDTH, HEIGHT, FPS); running = true; @@ -50,11 +68,15 @@ int main(int argc, char**argv) { app::Renderer renderer(plane, linesize, WIDTH, HEIGHT); + wsconn.Subscribe("ChatBotLog", &ws_handler, &renderer); + stream.Start(); std::cout << std::endl; while (running) { + loop.TryStep(); + const int64_t target = stream.VideoElapsedMS(); const int64_t elapsed = stream.TimeElapsedMS(); const int64_t difference = target - elapsed; @@ -62,7 +84,7 @@ int main(int argc, char**argv) { stream.PrepareVideoFrame(); if (stream.GetVideoFrameCounter() > 0 && difference < 0) { - std::cout << (difference / 1000.0) << "s behind schedule, dropping frame" << std::endl; + std::cout << (difference / -1000.0) << "s behind schedule, dropping frame" << std::endl; } else { renderer.RenderVideoFrame(stream.GetVideoFrameCounter(), target); } @@ -79,9 +101,9 @@ int main(int argc, char**argv) { stream.PushAudioFrame(); } - if (stream.GetVideoFrameCounter() % 60 == 59) { - std::cout << "rendered: " << (target / 1000.0) << "s, elapsed: " << (elapsed / 1000.0) << "s, difference: " << (difference / 1000.0) << 's' << std::endl; - } + //if (stream.GetVideoFrameCounter() % 60 == 59) { + // std::cout << "rendered: " << (target / 1000.0) << "s, elapsed: " << (elapsed / 1000.0) << "s, difference: " << (difference / 1000.0) << 's' << std::endl; + //} if (difference > 3000) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } @@ -89,6 +111,7 @@ int main(int argc, char**argv) { std::cout << std::endl; + wsctx.Shutdown(); stream.Finish(); return 0; diff --git a/src/uv/Error.h b/src/uv/Error.h new file mode 100644 index 0000000..9e600db --- /dev/null +++ b/src/uv/Error.h @@ -0,0 +1,29 @@ +#ifndef TEST_UV_ERROR_H_ +#define TEST_UV_ERROR_H_ + +#include +#include + +#include + +namespace { +std::string uv_make_message(const std::string &msg, int status) { + return msg + ": " + std::string(uv_strerror(status)); +} +} + +namespace uv { + +class Error: public std::runtime_error { + +public: + Error(const std::string &msg, int status): std::runtime_error(uv_make_message(msg, status)) { + } + ~Error() { + } + +}; + +} + +#endif diff --git a/src/uv/Loop.h b/src/uv/Loop.h new file mode 100644 index 0000000..de9d91f --- /dev/null +++ b/src/uv/Loop.h @@ -0,0 +1,49 @@ +#ifndef TEST_UV_LOOP_H_ +#define TEST_UV_LOOP_H_ + +#include + +#include "Error.h" + +namespace uv { + +class Loop { + +public: + Loop() { + int res = uv_loop_init(&loop); + if (res < 0) { + throw Error("failed to initialize loop", res); + } + } + ~Loop() { + uv_loop_close(&loop); + } + + Loop(const Loop &) = delete; + Loop &operator =(const Loop &) = delete; + +public: + uv_loop_t *GetLoop() { + return &loop; + } + +public: + void Run() { + uv_run(&loop, UV_RUN_DEFAULT); + } + void Step() { + uv_run(&loop, UV_RUN_ONCE); + } + void TryStep() { + uv_run(&loop, UV_RUN_NOWAIT); + } + +private: + uv_loop_t loop; + +}; + +} + +#endif diff --git a/src/uv/Signal.h b/src/uv/Signal.h new file mode 100644 index 0000000..35cd88d --- /dev/null +++ b/src/uv/Signal.h @@ -0,0 +1,46 @@ +#ifndef TEST_UV_LOOP_H_ +#define TEST_UV_LOOP_H_ + +#include + +#include "Error.h" + +namespace uv { + +class Signal { + +public: + Signal(uv_loop_t &loop, int sig, void *data, void (*handler)(void *, int)): handler(handler), data(data) { + int res = uv_signal_init(&loop, &signal); + if (res < 0) { + throw Error("failed to initialize loop", res); + } + res = uv_signal_start(&signal, &signal_handler, sig); + if (res < 0) { + throw Error("failed to install signal handler", res); + } + signal.data = this; + } + ~Signal() { + uv_signal_stop(&signal); + } + + Signal(const Signal &) = delete; + Signal &operator =(const Signal &) = delete; + +private: + static void signal_handler(uv_signal_t *sig, int signum) { + Signal *signal = static_cast(sig->data); + signal->handler(signal->data, signum); + } + +private: + uv_signal_t signal; + void (*handler)(void *, int); + void *data; + +}; + +} + +#endif diff --git a/src/ws/Connection.cpp b/src/ws/Connection.cpp new file mode 100644 index 0000000..6debd28 --- /dev/null +++ b/src/ws/Connection.cpp @@ -0,0 +1,88 @@ +#include "Connection.h" + +#include +#include +#include + +#include "io.h" + +namespace ws { + +Connection::Connection(lws_context *ctx) +: info{0}, wsi(nullptr), connected(false) { + info.context = ctx; + info.opaque_user_data = this; + // wss://alttp.localhorst.tv/app/nkmbiabdrtqnd8t19txs?protocol=7&client=js&version=8.3.0&flash=false + info.address = "alttp.localhorst.tv"; + info.port = 443; + info.ssl_connection = 1; + info.path = "/app/nkmbiabdrtqnd8t19txs?protocol=7&client=js&version=8.3.0&flash=false"; + info.host = "alttp.localhorst.tv"; + info.origin = "test"; + info.protocol = "pusher"; + info.ietf_version_or_minus_one = -1; + info.userdata = this; + info.pwsi = &wsi; + wsi = lws_client_connect_via_info(&info); + if (!wsi) { + throw std::runtime_error("failed to connect client"); + } + lws_set_timer_usecs(wsi, 30000000); + out_buffer.insert(0, LWS_PRE, '\0'); +} + +int Connection::ProtoCallback(lws_callback_reasons reason, void *in, size_t len) { + switch (reason) { + case LWS_CALLBACK_CLIENT_ESTABLISHED: + connected = true; + if (out_buffer.length() > LWS_PRE) { + lws_callback_on_writable(wsi); + } + break; + case LWS_CALLBACK_CLIENT_CLOSED: + connected = false; + break; + case LWS_CALLBACK_CLIENT_RECEIVE: + if (lws_is_first_fragment(wsi)) { + in_buffer.clear(); + } + in_buffer.append(static_cast(in), len); + if (lws_is_final_fragment(wsi)) { + HandleMessage(in_buffer); + } + break; + case LWS_CALLBACK_CLIENT_WRITEABLE: + if (out_buffer.length() > LWS_PRE) { + int res = lws_write(wsi, reinterpret_cast(&out_buffer[0]) + LWS_PRE, out_buffer.length() - LWS_PRE, LWS_WRITE_TEXT); + if (res > 0) { + out_buffer.erase(LWS_PRE, res); + } + break; + } + case LWS_CALLBACK_TIMER: + Ping(); + lws_set_timer_usecs(wsi, 30000000); + break; + case LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL: + case LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL: + case LWS_CALLBACK_WS_CLIENT_BIND_PROTOCOL: + case LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL: + case LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION: + case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: + case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: + case LWS_CALLBACK_CLOSED_CLIENT_HTTP: + case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: + case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: + case LWS_CALLBACK_WSI_CREATE: + break; + default: + std::cout << "unhandled connection proto callback, reason: " << reason << ", in: " << in << ", len: " << len << std::endl; + if (in && len) { + std::cout << " DATA: \"" << std::string(static_cast(in), len) << '"' << std::endl; + } + break; + } + return 0; +} + +} diff --git a/src/ws/Connection.h b/src/ws/Connection.h new file mode 100644 index 0000000..76ec576 --- /dev/null +++ b/src/ws/Connection.h @@ -0,0 +1,91 @@ +#ifndef TEST_WS_CONNECTION_H_ +#define TEST_WS_CONNECTION_H_ + +#include "json/reader.h" +#include "json/value.h" +#include "json/writer.h" +#include +#include +#include + +#include +#include +#include + +namespace ws { + +class Connection { + +public: + explicit Connection(lws_context *ctx); + ~Connection() { + } + + Connection(const Connection &) = delete; + Connection &operator =(const Connection &) = delete; + +private: + struct Callback { + void *user; + void (*callback)(void *, const Json::Value &); + void Call(const Json::Value &val) const { + (*callback)(user, val); + } + }; + +public: + void Ping() { + SendMessage("{\"event\":\"pusher:ping\"}"); + } + + void Subscribe(const std::string &chan, void (*callback)(void *, const Json::Value &), void *user = nullptr) { + callbacks[chan].push_back({ user, callback }); + Json::Value json; + json["event"] = "pusher:subscribe"; + json["data"]["channel"] = chan; + SendMessage(json); + } + + void SendMessage(const Json::Value &json) { + SendMessage(json_writer.write(json)); + } + + void SendMessage(const std::string &msg) { + out_buffer.append(msg); + lws_callback_on_writable(wsi); + } + + void SendMessage(const char *msg) { + out_buffer.append(msg); + lws_callback_on_writable(wsi); + } + +public: + int ProtoCallback(lws_callback_reasons reason, void *in, size_t len); + + void HandleMessage(const std::string &msg) { + Json::Value json; + json_reader.parse(msg, json); + const std::string channel = json["channel"].asString(); + for (const Callback &callback : callbacks[channel]) { + callback.Call(json); + } + } + +private: + lws_client_connect_info info; + lws *wsi; + bool connected; + + std::string in_buffer; + std::string out_buffer; + + Json::Reader json_reader; + Json::FastWriter json_writer; + std::map> callbacks; + +}; + +} + +#endif diff --git a/src/ws/Context.h b/src/ws/Context.h new file mode 100644 index 0000000..7d69981 --- /dev/null +++ b/src/ws/Context.h @@ -0,0 +1,92 @@ +#ifndef TEST_WS_CONTEXT_H_ +#define TEST_WS_CONTEXT_H_ + +#include +#include +#include +#include + +#include + +#include "Connection.h" +#include "io.h" +#include "../uv/Loop.h" + +namespace ws { + +class Context { + +public: + explicit Context(uv::Loop &loop): info{0}, ctx(nullptr), proto{0}, protos{0}, loops{0} { + //lws_set_log_level(LLL_USER|LLL_ERR|LLL_WARN|LLL_NOTICE|LLL_INFO|LLL_DEBUG, nullptr); + proto.name = "pusher"; + proto.callback = &proto_callback; + proto.user = this; + proto.rx_buffer_size = BUFSIZ; + proto.tx_packet_size = BUFSIZ; + protos[0] = &proto; + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_LIBUV; + info.port = CONTEXT_PORT_NO_LISTEN; + info.pprotocols = protos; + loops[0] = loop.GetLoop(); + info.foreign_loops = loops; + ctx = lws_create_context(&info); + if (!ctx) { + throw std::runtime_error("failed to create context"); + } + } + ~Context() { + lws_context_destroy(ctx); + } + + Context(const Context &) = delete; + Context &operator =(const Context &) = delete; + +public: + lws_context *GetContext() { + return ctx; + } + + void Shutdown() { + lws_context_deprecate(ctx, nullptr); + } + +private: + static int proto_callback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) { + void *user_data = lws_wsi_user(wsi); + if (user_data) { + Connection *conn = static_cast(user_data); + return conn->ProtoCallback(reason, in, len); + } + Context *c = static_cast(user); + return c->ProtoCallback(reason, in, len); + } + + int ProtoCallback(lws_callback_reasons reason, void *in, size_t len) { + switch (reason) { + case LWS_CALLBACK_PROTOCOL_INIT: + case LWS_CALLBACK_PROTOCOL_DESTROY: + case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: + break; + default: + std::cout << "unhandled generic proto callback, reason: " << reason << ", in: " << in << ", len: " << len << std::endl; + if (in && len) { + std::cout << " DATA: \"" << std::string(static_cast(in), len) << '"' << std::endl; + } + break; + } + return 0; + } + +private: + lws_context_creation_info info; + lws_protocols proto; + const lws_protocols *protos[2]; + void *loops[2]; + lws_context *ctx; + +}; + +} + +#endif diff --git a/src/ws/io.h b/src/ws/io.h new file mode 100644 index 0000000..b60d852 --- /dev/null +++ b/src/ws/io.h @@ -0,0 +1,370 @@ +#ifndef TEST_WS_IO_H_ +#define TEST_WS_IO_H_ + +#include + +extern "C" { +#include +} + +namespace std { +inline std::ostream &operator <<(std::ostream &out, lws_callback_reasons r) { + switch (r) { + case LWS_CALLBACK_PROTOCOL_INIT: + out << "protocol init"; + break; + case LWS_CALLBACK_PROTOCOL_DESTROY: + out << "protocol destroy"; + break; + case LWS_CALLBACK_WSI_CREATE: + out << "wsi create"; + break; + case LWS_CALLBACK_WSI_DESTROY: + out << "wsi destroy"; + break; + case LWS_CALLBACK_WSI_TX_CREDIT_GET: + out << "wsi tx credit get"; + break; + + case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: + out << "load extra client certs"; + break; + case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: + out << "load extra server certs"; + break; + case LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION: + out << "perform server cert verify"; + break; + case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: + out << "perform client cert verify"; + break; + case LWS_CALLBACK_SSL_INFO: + out << "ssl info"; + break; + + case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: + out << "new client instance"; + break; + case LWS_CALLBACK_HTTP: + out << "http request"; + break; + case LWS_CALLBACK_HTTP_BODY: + out << "http body"; + break; + case LWS_CALLBACK_HTTP_BODY_COMPLETION: + out << "http body complete"; + break; + case LWS_CALLBACK_HTTP_FILE_COMPLETION: + out << "http file complete"; + break; + case LWS_CALLBACK_HTTP_WRITEABLE: + out << "http writable"; + break; + case LWS_CALLBACK_CLOSED_HTTP: + out << "http closed"; + break; + case LWS_CALLBACK_FILTER_HTTP_CONNECTION: + out << "filter http connection"; + break; + case LWS_CALLBACK_ADD_HEADERS: + out << "add headers"; + break; + case LWS_CALLBACK_VERIFY_BASIC_AUTHORIZATION: + out << "verify basic auth"; + break; + case LWS_CALLBACK_CHECK_ACCESS_RIGHTS: + out << "check access rights"; + break; + case LWS_CALLBACK_PROCESS_HTML: + out << "process html"; + break; + case LWS_CALLBACK_HTTP_BIND_PROTOCOL: + out << "http bind protocol"; + break; + case LWS_CALLBACK_HTTP_DROP_PROTOCOL: + out << "http drop protocol"; + break; + case LWS_CALLBACK_HTTP_CONFIRM_UPGRADE: + out << "http confirm upgrade"; + break; + + case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: + out << "http client connection established"; + break; + case LWS_CALLBACK_CLOSED_CLIENT_HTTP: + out << "http client connection closed"; + break; + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: + out << "http client read"; + break; + case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: + out << "http client completed"; + break; + case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE: + out << "http client writable"; + break; + case LWS_CALLBACK_CLIENT_HTTP_REDIRECT: + out << "http client redirect"; + break; + case LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL: + out << "http client bind protocol"; + break; + case LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL: + out << "http client drop protocol"; + break; + + case LWS_CALLBACK_ESTABLISHED: + out << "connection established"; + break; + case LWS_CALLBACK_CLOSED: + out << "connection closed"; + break; + case LWS_CALLBACK_SERVER_WRITEABLE: + out << "server writable"; + break; + case LWS_CALLBACK_RECEIVE: + out << "receive"; + break; + case LWS_CALLBACK_RECEIVE_PONG: + out << "receive pong"; + break; + case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: + out << "peer initiated close"; + break; + case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: + out << "filter protocol connection"; + break; + case LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: + out << "confirm extension ok"; + break; + case LWS_CALLBACK_WS_SERVER_BIND_PROTOCOL: + out << "ws server bind protocol"; + break; + case LWS_CALLBACK_WS_SERVER_DROP_PROTOCOL: + out << "ws server drop protocol"; + break; + + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + out << "client connection error"; + break; + case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: + out << "client filter pre establish"; + break; + case LWS_CALLBACK_CLIENT_ESTABLISHED: + out << "client connection established"; + break; + case LWS_CALLBACK_CLIENT_CLOSED: + out << "client connection closed"; + break; + case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: + out << "client append handshake header"; + break; + case LWS_CALLBACK_CLIENT_RECEIVE: + out << "client receive"; + break; + case LWS_CALLBACK_CLIENT_RECEIVE_PONG: + out << "client receive pong"; + break; + case LWS_CALLBACK_CLIENT_WRITEABLE: + out << "client writable"; + break; + case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: + out << "client confirm extension suppported"; + break; + case LWS_CALLBACK_WS_EXT_DEFAULTS: + out << "ws ext defaults"; + break; + case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: + out << "filter network connection"; + break; + case LWS_CALLBACK_WS_CLIENT_BIND_PROTOCOL: + out << "ws client bind protocol"; + break; + case LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL: + out << "ws client drop protocol"; + break; + + case LWS_CALLBACK_GET_THREAD_ID: + out << "get thread id"; + break; + case LWS_CALLBACK_ADD_POLL_FD: + out << "add poll fd"; + break; + case LWS_CALLBACK_DEL_POLL_FD: + out << "del poll fd"; + break; + case LWS_CALLBACK_CHANGE_MODE_POLL_FD: + out << "change mode poll fd"; + break; + case LWS_CALLBACK_LOCK_POLL: + out << "lock poll"; + break; + case LWS_CALLBACK_UNLOCK_POLL: + out << "unlock poll"; + break; + + case LWS_CALLBACK_CGI: + out << "cgi"; + break; + case LWS_CALLBACK_CGI_TERMINATED: + out << "cgi terminated"; + break; + case LWS_CALLBACK_CGI_STDIN_DATA: + out << "cgi stdin data"; + break; + case LWS_CALLBACK_CGI_STDIN_COMPLETED: + out << "cgi stdin completed"; + break; + case LWS_CALLBACK_CGI_PROCESS_ATTACH: + out << "cgi process attach"; + break; + + case LWS_CALLBACK_SESSION_INFO: + out << "session info"; + break; + case LWS_CALLBACK_GS_EVENT: + out << "gs event"; + break; + case LWS_CALLBACK_HTTP_PMO: + out << "http pmo"; + break; + + case LWS_CALLBACK_RAW_PROXY_CLI_RX: + out << "raw proxy cli rx"; + break; + case LWS_CALLBACK_RAW_PROXY_SRV_RX: + out << "raw proxy srv rx"; + break; + case LWS_CALLBACK_RAW_PROXY_CLI_CLOSE: + out << "raw proxy cli close"; + break; + case LWS_CALLBACK_RAW_PROXY_SRV_CLOSE: + out << "raw proxy srv close"; + break; + case LWS_CALLBACK_RAW_PROXY_CLI_WRITEABLE: + out << "raw proxy cli writable"; + break; + case LWS_CALLBACK_RAW_PROXY_SRV_WRITEABLE: + out << "raw proxy srv writable"; + break; + case LWS_CALLBACK_RAW_PROXY_CLI_ADOPT: + out << "raw proxy cli adopt"; + break; + case LWS_CALLBACK_RAW_PROXY_SRV_ADOPT: + out << "raw proxy srv adopt"; + break; + case LWS_CALLBACK_RAW_PROXY_CLI_BIND_PROTOCOL: + out << "raw proxy cli bind protocol"; + break; + case LWS_CALLBACK_RAW_PROXY_SRV_BIND_PROTOCOL: + out << "raw proxy srv bind protocol"; + break; + case LWS_CALLBACK_RAW_PROXY_CLI_DROP_PROTOCOL: + out << "raw proxy cli drop protocol"; + break; + case LWS_CALLBACK_RAW_PROXY_SRV_DROP_PROTOCOL: + out << "raw proxy srv drop protocol"; + break; + + case LWS_CALLBACK_RAW_RX: + out << "raw rx"; + break; + case LWS_CALLBACK_RAW_CLOSE: + out << "raw close"; + break; + case LWS_CALLBACK_RAW_WRITEABLE: + out << "raw writable"; + break; + case LWS_CALLBACK_RAW_ADOPT: + out << "raw adopt"; + break; + case LWS_CALLBACK_RAW_CONNECTED: + out << "raw connected"; + break; + case LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL: + out << "raw skt bind protocol"; + break; + case LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL: + out << "raw skt drop protocol"; + break; + + case LWS_CALLBACK_RAW_ADOPT_FILE: + out << "raw adopt file"; + break; + case LWS_CALLBACK_RAW_RX_FILE: + out << "raw rx file"; + break; + case LWS_CALLBACK_RAW_WRITEABLE_FILE: + out << "raw writable file"; + break; + case LWS_CALLBACK_RAW_CLOSE_FILE: + out << "raw close file"; + break; + case LWS_CALLBACK_RAW_FILE_BIND_PROTOCOL: + out << "raw file bind protocol"; + break; + case LWS_CALLBACK_RAW_FILE_DROP_PROTOCOL: + out << "raw file drop protocol"; + break; + + case LWS_CALLBACK_TIMER: + out << "timer"; + break; + case LWS_CALLBACK_EVENT_WAIT_CANCELLED: + out << "event wait cancelled"; + break; + case LWS_CALLBACK_CHILD_CLOSING: + out << "child closing"; + break; + + case LWS_CALLBACK_VHOST_CERT_AGING: + out << "vhost cert aging"; + break; + case LWS_CALLBACK_VHOST_CERT_UPDATE: + out << "vhost cert update"; + break; + + case LWS_CALLBACK_MQTT_NEW_CLIENT_INSTANTIATED: + out << "mqtt new client instantiated"; + break; + case LWS_CALLBACK_MQTT_IDLE: + out << "mqtt idle"; + break; + case LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED: + out << "mqtt client established"; + break; + case LWS_CALLBACK_MQTT_SUBSCRIBED: + out << "mqtt subscribed"; + break; + case LWS_CALLBACK_MQTT_CLIENT_WRITEABLE: + out << "mqtt client writable"; + break; + case LWS_CALLBACK_MQTT_CLIENT_RX: + out << "mqtt client rx"; + break; + case LWS_CALLBACK_MQTT_UNSUBSCRIBED: + out << "mqtt unsubscribed"; + break; + case LWS_CALLBACK_MQTT_DROP_PROTOCOL: + out << "mqtt drop protocol"; + break; + case LWS_CALLBACK_MQTT_CLIENT_CLOSED: + out << "mqtt client closed"; + break; + case LWS_CALLBACK_MQTT_ACK: + out << "mqtt ack"; + break; + case LWS_CALLBACK_MQTT_RESEND: + out << "mqtt resend"; + break; + + default: + out << "unknown reason"; + break; + } + out << " (" << int(r) << ')'; + return out; +} +} + +#endif