From 7abcfc0390bb778d7830be3d3ef5585628e0ba66 Mon Sep 17 00:00:00 2001 From: kiralycraft Date: Sun, 28 Feb 2021 15:52:47 +0200 Subject: [PATCH] Added ability to stream specific monitor on Linux --- CMakeLists.txt | 1 + assets/sunshine.conf | 11 +- sunshine/config.h | 2 + sunshine/platform/linux/display.cpp | 751 +++++++++++++++++----------- 4 files changed, 463 insertions(+), 302 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01e933ff..177ce096 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ else() xcb xcb-shm xcb-xfixes + Xrandr ${X11_LIBRARIES} evdev pulse diff --git a/assets/sunshine.conf b/assets/sunshine.conf index 3fabb634..b0216ada 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -93,6 +93,9 @@ # adapter_name = Radeon RX 580 Series # output_name = \\.\DISPLAY1 +# !! Linux only !! +# Set the display number to stream. I have no idea how they are numbered. They start from 0. +linux_monitor_id = 3 ############################################### # FFmpeg software encoding parameters @@ -102,7 +105,7 @@ # Constant Rate Factor. Between 1 and 52. It allows QP to go up during motion and down with still image, resulting in constant perceived quality # Higher value means more compression, but less quality # If crf == 0, then use QP directly instead -# crf = 0 +crf = 18 # Quantitization Parameter # Higher value means more compression, but less quality @@ -113,7 +116,7 @@ # Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually # worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest # value that can reliably encode at your desired streaming settings on your hardware. -# min_threads = 1 +min_threads = 1 # Allows the client to request HEVC Main or HEVC Main10 video streams. # HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding. @@ -121,14 +124,14 @@ # If set to 1, Sunshine will not advertise support for HEVC # If set to 2, Sunshine will advertise support for HEVC Main profile # If set to 3, Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles -# hevc_mode = 0 +hevc_mode = 0 # Force a specific encoder, otherwise Sunshine will use the first encoder that is available # supported encoders: # nvenc # software # -# encoder = nvenc +# encoder = vaapi ##################################### Software ##################################### # See x264 --fullhelp for the different presets # sw_preset = superfast diff --git a/sunshine/config.h b/sunshine/config.h index 9c14b1fe..0102fd84 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -29,6 +29,8 @@ struct video_t { std::string encoder; std::string adapter_name; std::string output_name; + + int linux_monitor_id; //Only used on linux }; struct audio_t { diff --git a/sunshine/platform/linux/display.cpp b/sunshine/platform/linux/display.cpp index 1452920e..b3869d92 100644 --- a/sunshine/platform/linux/display.cpp +++ b/sunshine/platform/linux/display.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -26,11 +27,12 @@ #include "sunshine/config.h" #include "sunshine/main.h" -namespace platf { +namespace platf +{ using namespace std::literals; -void freeImage(XImage *); -void freeX(XFixesCursorImage *); +void freeImage(XImage*); +void freeX(XFixesCursorImage*); using ifaddr_t = util::safe_ptr; using xcb_connect_t = util::safe_ptr; @@ -41,407 +43,560 @@ using xdisplay_t = util::safe_ptr_v2; using ximg_t = util::safe_ptr; using xcursor_t = util::safe_ptr; -class shm_id_t { +class shm_id_t +{ public: - shm_id_t() : id { -1 } {} - shm_id_t(int id) : id {id } {} - shm_id_t(shm_id_t &&other) noexcept : id(other.id) { - other.id = -1; - } + shm_id_t() : id { -1 } + { + } + shm_id_t(int id) : id { id } + { + } + shm_id_t(shm_id_t &&other) noexcept : id(other.id) + { + other.id = -1; + } - ~shm_id_t() { - if(id != -1) { - shmctl(id, IPC_RMID, nullptr); - id = -1; - } - } - int id; + ~shm_id_t() + { + if (id != -1) + { + shmctl(id, IPC_RMID, nullptr); + id = -1; + } + } + int id; }; -class shm_data_t { +class shm_data_t +{ public: - shm_data_t() : data {(void*)-1 } {} - shm_data_t(void *data) : data {data } {} + shm_data_t() : data { (void*) -1 } + { + } + shm_data_t(void *data) : data { data } + { + } - shm_data_t(shm_data_t &&other) noexcept : data(other.data) { - other.data = (void*)-1; - } + shm_data_t(shm_data_t &&other) noexcept : data(other.data) + { + other.data = (void*) -1; + } - ~shm_data_t() { - if((std::uintptr_t)data != -1) { - shmdt(data); - data = (void*)-1; - } - } + ~shm_data_t() + { + if ((std::uintptr_t) data != -1) + { + shmdt(data); + data = (void*) -1; + } + } - void *data; + void *data; }; -struct x11_img_t : public img_t { - ximg_t img; +struct x11_img_t: public img_t +{ + ximg_t img; }; -struct shm_img_t : public img_t { - ~shm_img_t() override { - delete[] data; - data = nullptr; - } +struct shm_img_t: public img_t +{ + ~shm_img_t() override + { + delete[] data; + data = nullptr; + } }; -void blend_cursor(Display *display, img_t &img) { - xcursor_t overlay { XFixesGetCursorImage(display) }; +void blend_cursor(Display *display, img_t &img, int offsetX,int offsetY) +{ + xcursor_t overlay { XFixesGetCursorImage(display) }; - if(!overlay) { - BOOST_LOG(error) << "Couldn't get cursor from XFixesGetCursorImage"sv; - return; - } + if (!overlay) + { + BOOST_LOG(error) + << "Couldn't get cursor from XFixesGetCursorImage"sv; + return; + } - overlay->x -= overlay->xhot; - overlay->y -= overlay->yhot; + overlay->x -= overlay->xhot; + overlay->y -= overlay->yhot; - overlay->x = std::max((short)0, overlay->x); - overlay->y = std::max((short)0, overlay->y); + overlay->x -= offsetX; + overlay->y -= offsetY; - auto pixels = (int*)img.data; + overlay->x = std::max((short) 0, overlay->x); + overlay->y = std::max((short) 0, overlay->y); - auto screen_height = img.height; - auto screen_width = img.width; + auto pixels = (int*) img.data; - auto delta_height = std::min(overlay->height, std::max(0, screen_height - overlay->y)); - auto delta_width = std::min(overlay->width, std::max(0, screen_width - overlay->x)); - for(auto y = 0; y < delta_height; ++y) { + auto screen_height = img.height; + auto screen_width = img.width; - auto overlay_begin = &overlay->pixels[y * overlay->width]; - auto overlay_end = &overlay->pixels[y * overlay->width + delta_width]; + auto delta_height = std::min(overlay->height,std::max(0, screen_height - overlay->y)); + auto delta_width = std::min(overlay->width,std::max(0, screen_width - overlay->x)); + for (auto y = 0; y < delta_height; ++y) + { + auto overlay_begin = &overlay->pixels[y * overlay->width]; + auto overlay_end = &overlay->pixels[y * overlay->width + delta_width]; - auto pixels_begin = &pixels[(y + overlay->y) * (img.row_pitch / img.pixel_pitch) + overlay->x]; - std::for_each(overlay_begin, overlay_end, [&](long pixel) { - int *pixel_p = (int*)&pixel; + auto pixels_begin = &pixels[(y + overlay->y)* (img.row_pitch / img.pixel_pitch) + overlay->x]; - auto colors_in = (uint8_t*)pixels_begin; + std::for_each(overlay_begin, overlay_end,[&](long pixel) + { + int *pixel_p = (int*) &pixel; - auto alpha = (*(uint*)pixel_p) >> 24u; - if(alpha == 255) { - *pixels_begin = *pixel_p; - } - else { - auto colors_out = (uint8_t*)pixel_p; - colors_in[0] = colors_out[0] + (colors_in[0] * (255 - alpha) + 255/2) / 255; - colors_in[1] = colors_out[1] + (colors_in[1] * (255 - alpha) + 255/2) / 255; - colors_in[2] = colors_out[2] + (colors_in[2] * (255 - alpha) + 255/2) / 255; - } - ++pixels_begin; - }); - } + auto colors_in = (uint8_t*) pixels_begin; + + auto alpha = (*(uint*) pixel_p) >> 24u; + if (alpha == 255) + { + *pixels_begin = *pixel_p; + } + else + { + auto colors_out = (uint8_t*) pixel_p; + colors_in[0] = colors_out[0] + (colors_in[0] * (255 - alpha) +255 /2) / 255; + colors_in[1] = colors_out[1] + (colors_in[1] * (255 - alpha) + 255 / 2) / 255; + colors_in[2] = colors_out[2] + (colors_in[2] * (255 - alpha) + 255 / 2) / 255; + } + ++pixels_begin; + }); + } } -struct x11_attr_t : public display_t { - x11_attr_t() : xdisplay {XOpenDisplay(nullptr) }, xwindow { }, xattr {} { - if(!xdisplay) { - BOOST_LOG(fatal) << "Could not open x11 display"sv; - log_flush(); - std::abort(); - } +struct x11_attr_t: public display_t +{ + xdisplay_t xdisplay; + Window xwindow; + XWindowAttributes xattr; - xwindow = DefaultRootWindow(xdisplay.get()); + Display* displayDisplay; - refresh(); + /* + * Remember last X (NOT the streamed monitor!) size. This way we can trigger reinitialization if the dimensions changed while streaming + */ + int lastWidth,lastHeight; - width = xattr.width; - height = xattr.height; - } + /* + * Offsets for when streaming a specific monitor. By default, they are 0. + */ + int displayOffsetX,displayOffsetY; - void refresh() { - XGetWindowAttributes(xdisplay.get(), xwindow, &xattr); - } + x11_attr_t() : xdisplay { displayDisplay = XOpenDisplay(nullptr) }, xwindow { }, xattr { } + { + XInitThreads(); + if (!xdisplay) + { + BOOST_LOG(fatal) + << "Could not open x11 display"sv; + log_flush(); + std::abort(); + } - capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) override { - refresh(); + xwindow = DefaultRootWindow(xdisplay.get()); - if(width != xattr.width || height != xattr.height) { - return capture_e::reinit; - } + refresh(); - XImage *img { XGetImage( - xdisplay.get(), - xwindow, - 0, 0, - xattr.width, xattr.height, - AllPlanes, ZPixmap) - }; + int streamedMonitor = config::video.linux_monitor_id; - auto img_out = (x11_img_t*)img_out_base; - img_out->width = img->width; - img_out->height = img->height; - img_out->data = (uint8_t*)img->data; - img_out->row_pitch = img->bytes_per_line; - img_out->pixel_pitch = img->bits_per_pixel / 8; - img_out->img.reset(img); + if (streamedMonitor != -1) //If the value has been set at all + { + BOOST_LOG(warning) << "Configuring selected monitor to stream. If it fails here, you may need Xrandr >= 1.5"sv; + XRRScreenResources *screenr = XRRGetScreenResources(displayDisplay, xwindow); + // This is the key right here. Use XRRScreenResources::noutput + int output = screenr->noutput; - if(cursor) { - blend_cursor(xdisplay.get(), *img_out_base); - } + if (streamedMonitor >= output) + { + BOOST_LOG(error)<< "Could not stream selected display number because there aren't so many."sv; + } + else + { + XRROutputInfo* out_info = XRRGetOutputInfo(displayDisplay, screenr, screenr->outputs[streamedMonitor]); + if (NULL == out_info || out_info->connection != RR_Connected) + { + BOOST_LOG(error)<< "Could not stream selected display because it doesn't seem to be connected"sv; + } + else + { + XRRCrtcInfo* crt_info = XRRGetCrtcInfo(displayDisplay, screenr, out_info->crtc); + BOOST_LOG(info)<<"Streaming display: "<name<<" with res "<width<<" x "<height<<+" offset by "<x<<" x "<y<<"."sv; - return capture_e::ok; - } + width = crt_info -> width; + height = crt_info -> height; + displayOffsetX = crt_info -> x; + displayOffsetY = crt_info -> y; - std::shared_ptr alloc_img() override { - return std::make_shared(); - } + XRRFreeCrtcInfo(crt_info); + } + XRRFreeOutputInfo(out_info); + } + XRRFreeScreenResources(screenr); + } + else + { + width = xattr.width; + height = xattr.height; + } - int dummy_img(img_t *img) override { - snapshot(img, 0s, true); - return 0; - } + lastWidth = xattr.width; + lastHeight = xattr.height; + } - xdisplay_t xdisplay; - Window xwindow; - XWindowAttributes xattr; + /** + * Called when the display attributes should change. + */ + void refresh() + { + XGetWindowAttributes(xdisplay.get(), xwindow, &xattr); //Update xattr's + } + + capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) override + { + refresh(); + capture_e toReturn; + if (xattr.width != lastWidth || xattr.height != lastHeight) //The whole X server changed, so we gotta reinit everything + { + BOOST_LOG(warning)<< "X dimensions changed in non-SHM mode, request reinit"sv; + toReturn = capture_e::reinit; + } + else + { + XImage *img { XGetImage(xdisplay.get(), xwindow, displayOffsetX, displayOffsetY, width,height, AllPlanes, ZPixmap) }; + + auto img_out = (x11_img_t*) img_out_base; + img_out->width = img->width; + img_out->height = img->height; + img_out->data = (uint8_t*) img->data; + img_out->row_pitch = img->bytes_per_line; + img_out->pixel_pitch = img->bits_per_pixel / 8; + img_out->img.reset(img); + + if (cursor) + { + blend_cursor(xdisplay.get(), *img_out_base,displayOffsetX,displayOffsetY); + } + toReturn = capture_e::ok; + } + return toReturn; + } + + std::shared_ptr alloc_img() override + { + return std::make_shared(); + } + + int dummy_img(img_t *img) override + { + snapshot(img, 0s, true); + return 0; + } }; -struct shm_attr_t : public x11_attr_t { - xdisplay_t shm_xdisplay; // Prevent race condition with x11_attr_t::xdisplay - xcb_connect_t xcb; - xcb_screen_t *display; - std::uint32_t seg; +struct shm_attr_t: public x11_attr_t +{ + xdisplay_t shm_xdisplay; // Prevent race condition with x11_attr_t::xdisplay + xcb_connect_t xcb; + xcb_screen_t *display; + std::uint32_t seg; - shm_id_t shm_id; + shm_id_t shm_id; - shm_data_t data; + shm_data_t data; - util::TaskPool::task_id_t refresh_task_id; - void delayed_refresh() { - refresh(); + util::TaskPool::task_id_t refresh_task_id; + void delayed_refresh() + { + refresh(); - refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id; - } + refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh,2s, this).task_id; + } - shm_attr_t() : x11_attr_t(), shm_xdisplay {XOpenDisplay(nullptr) } { - refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh, 2s, this).task_id; - } + shm_attr_t() : x11_attr_t(), shm_xdisplay { XOpenDisplay(nullptr) } + { + refresh_task_id = task_pool.pushDelayed(&shm_attr_t::delayed_refresh,2s, this).task_id; + } - ~shm_attr_t() override { - while(!task_pool.cancel(refresh_task_id)); - } + ~shm_attr_t() override + { + while (!task_pool.cancel(refresh_task_id)); + } - capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor) override { - if(width != xattr.width || height != xattr.height) { - return capture_e::reinit; - } + capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor) override + { + capture_e toReturn; + if (xattr.width != lastWidth || xattr.height != lastHeight) //The whole X server changed, so we gotta reinit everything + { + BOOST_LOG(warning)<< "X dimensions changed in SHM mode, request reinit"sv; + toReturn = capture_e::reinit; + } + else + { + auto img_cookie = xcb_shm_get_image_unchecked(xcb.get(), display->root,displayOffsetX, displayOffsetY, width, height, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP, seg, 0); - auto img_cookie = xcb_shm_get_image_unchecked( - xcb.get(), - display->root, - 0, 0, - width, height, - ~0, - XCB_IMAGE_FORMAT_Z_PIXMAP, - seg, - 0 - ); + xcb_img_t img_reply { xcb_shm_get_image_reply(xcb.get(), img_cookie,nullptr) }; + if (!img_reply) + { + BOOST_LOG(error) + << "Could not get image reply"sv; + return capture_e::reinit; + } - xcb_img_t img_reply { xcb_shm_get_image_reply(xcb.get(), img_cookie, nullptr) }; - if(!img_reply) { - BOOST_LOG(error) << "Could not get image reply"sv; - return capture_e::reinit; - } + std::copy_n((std::uint8_t*) data.data, frame_size(), img->data); - std::copy_n((std::uint8_t*)data.data, frame_size(), img->data); + if (cursor) + { + blend_cursor(shm_xdisplay.get(), *img,displayOffsetX,displayOffsetY); + } - if(cursor) { - blend_cursor(shm_xdisplay.get(), *img); - } + toReturn = capture_e::ok; + } + return toReturn; + } - return capture_e::ok; - } + std::shared_ptr alloc_img() override + { + auto img = std::make_shared(); + img->width = width; + img->height = height; + img->pixel_pitch = 4; + img->row_pitch = img->pixel_pitch * width; + img->data = new std::uint8_t[height * img->row_pitch]; - std::shared_ptr alloc_img() override { - auto img = std::make_shared(); - img->width = width; - img->height = height; - img->pixel_pitch = 4; - img->row_pitch = img->pixel_pitch * width; - img->data = new std::uint8_t[height * img->row_pitch]; + return img; + } - return img; - } + int dummy_img(platf::img_t *img) override + { + return 0; + } - int dummy_img(platf::img_t *img) override { - return 0; - } + int init() + { + shm_xdisplay.reset(XOpenDisplay(nullptr)); + xcb.reset(xcb_connect(nullptr, nullptr)); + if (xcb_connection_has_error(xcb.get())) + { + return -1; + } - int init() { - shm_xdisplay.reset(XOpenDisplay(nullptr)); - xcb.reset(xcb_connect(nullptr, nullptr)); - if(xcb_connection_has_error(xcb.get())) { - return -1; - } + if (!xcb_get_extension_data(xcb.get(), &xcb_shm_id)->present) + { + BOOST_LOG(error) + << "Missing SHM extension"sv; - if(!xcb_get_extension_data(xcb.get(), &xcb_shm_id)->present) { - BOOST_LOG(error) << "Missing SHM extension"sv; + return -1; + } - return -1; - } + auto iter = xcb_setup_roots_iterator(xcb_get_setup(xcb.get())); + display = iter.data; + seg = xcb_generate_id(xcb.get()); - auto iter = xcb_setup_roots_iterator(xcb_get_setup(xcb.get())); - display = iter.data; - seg = xcb_generate_id(xcb.get()); + shm_id.id = shmget(IPC_PRIVATE, frame_size(), IPC_CREAT | 0777); + if (shm_id.id == -1) + { + BOOST_LOG(error) + << "shmget failed"sv; + return -1; + } - shm_id.id = shmget(IPC_PRIVATE, frame_size(), IPC_CREAT | 0777); - if(shm_id.id == -1) { - BOOST_LOG(error) << "shmget failed"sv; - return -1; - } + xcb_shm_attach(xcb.get(), seg, shm_id.id, false); + data.data = shmat(shm_id.id, nullptr, 0); - xcb_shm_attach(xcb.get(), seg, shm_id.id, false); - data.data = shmat(shm_id.id, nullptr, 0); + if ((uintptr_t) data.data == -1) + { + BOOST_LOG(error) + << "shmat failed"sv; - if ((uintptr_t)data.data == -1) { - BOOST_LOG(error) << "shmat failed"sv; + return -1; + } - return -1; - } + /* + * Commented out resetting of the sizes when intializing X in SHM mode. It might be wrong. Expect issues. This is the default mode, so poisoning those variables is not desired + */ +// width = display->width_in_pixels; +// height = display->height_in_pixels; - width = display->width_in_pixels; - height = display->height_in_pixels; + return 0; + } - return 0; - } - - std::uint32_t frame_size() { - return width * height * 4; - } + std::uint32_t frame_size() + { + return width * height * 4; + } }; -struct mic_attr_t : public mic_t { - pa_sample_spec ss; - util::safe_ptr mic; +struct mic_attr_t: public mic_t +{ + pa_sample_spec ss; + util::safe_ptr mic; - explicit mic_attr_t(pa_sample_format format, std::uint32_t sample_rate, std::uint8_t channels) : ss { format, sample_rate, channels }, mic {} {} - capture_e sample(std::vector &sample_buf) override { - auto sample_size = sample_buf.size(); + explicit mic_attr_t(pa_sample_format format, std::uint32_t sample_rate, + std::uint8_t channels) : ss { format, sample_rate, channels }, mic { } + { + } + capture_e sample(std::vector &sample_buf) override + { + auto sample_size = sample_buf.size(); - auto buf = sample_buf.data(); - int status; - if(pa_simple_read(mic.get(), buf, sample_size * 2, &status)) { - BOOST_LOG(error) << "pa_simple_read() failed: "sv << pa_strerror(status); + auto buf = sample_buf.data(); + int status; + if (pa_simple_read(mic.get(), buf, sample_size * 2, &status)) + { + BOOST_LOG(error) + << "pa_simple_read() failed: "sv << pa_strerror(status); - return capture_e::error; - } + return capture_e::error; + } - return capture_e::ok; - } + return capture_e::ok; + } }; -std::shared_ptr shm_display() { - auto shm = std::make_shared(); +std::shared_ptr shm_display() +{ + auto shm = std::make_shared(); - if(shm->init()) { - return nullptr; - } + if (shm->init()) + { + return nullptr; + } - return shm; + return shm; } -std::shared_ptr display(platf::dev_type_e hwdevice_type) { - if(hwdevice_type != platf::dev_type_e::none) { - return nullptr; - } +std::shared_ptr display(platf::dev_type_e hwdevice_type) +{ + if (hwdevice_type != platf::dev_type_e::none) + { + BOOST_LOG(error)<< "Could not initialize display with the given hw device type."sv; + return nullptr; + } - auto shm_disp = shm_display(); + auto shm_disp = shm_display(); //Attempt to use shared memory X11 to avoid copying the frame - if(!shm_disp) { - return std::make_shared(); - } + if (!shm_disp) + { + return std::make_shared(); //Fallback to standard way if else + } - return shm_disp; + return shm_disp; } -std::unique_ptr microphone(std::uint32_t sample_rate) { - auto mic = std::make_unique(PA_SAMPLE_S16LE, sample_rate, 2); +std::unique_ptr microphone(std::uint32_t sample_rate) +{ + auto mic = std::make_unique(PA_SAMPLE_S16LE, sample_rate, 2); - int status; + int status; - const char *audio_sink = "@DEFAULT_MONITOR@"; - if(!config::audio.sink.empty()) { - audio_sink = config::audio.sink.c_str(); - } + const char *audio_sink = "@DEFAULT_MONITOR@"; + if (!config::audio.sink.empty()) + { + audio_sink = config::audio.sink.c_str(); + } - mic->mic.reset( - pa_simple_new(nullptr, "sunshine", pa_stream_direction_t::PA_STREAM_RECORD, audio_sink, "sunshine-record", &mic->ss, nullptr, nullptr, &status) - ); + mic->mic.reset( + pa_simple_new(nullptr, "sunshine", + pa_stream_direction_t::PA_STREAM_RECORD, audio_sink, + "sunshine-record", &mic->ss, nullptr, nullptr, &status)); - if(!mic->mic) { - auto err_str = pa_strerror(status); - BOOST_LOG(error) << "pa_simple_new() failed: "sv << err_str; + if (!mic->mic) + { + auto err_str = pa_strerror(status); + BOOST_LOG(error) + << "pa_simple_new() failed: "sv << err_str; - log_flush(); - std::abort(); - } + log_flush(); + std::abort(); + } - return mic; + return mic; } -ifaddr_t get_ifaddrs() { - ifaddrs *p { nullptr }; +ifaddr_t get_ifaddrs() +{ + ifaddrs *p { nullptr }; - getifaddrs(&p); + getifaddrs(&p); - return ifaddr_t { p }; + return ifaddr_t { p }; } -std::string from_sockaddr(const sockaddr *const ip_addr) { - char data[INET6_ADDRSTRLEN]; +std::string from_sockaddr(const sockaddr *const ip_addr) +{ + char data[INET6_ADDRSTRLEN]; - auto family = ip_addr->sa_family; - if(family == AF_INET6) { - inet_ntop(AF_INET6, &((sockaddr_in6*)ip_addr)->sin6_addr, data, INET6_ADDRSTRLEN); - } + auto family = ip_addr->sa_family; + if (family == AF_INET6) + { + inet_ntop(AF_INET6, &((sockaddr_in6*) ip_addr)->sin6_addr, data, + INET6_ADDRSTRLEN); + } - if(family == AF_INET) { - inet_ntop(AF_INET, &((sockaddr_in*)ip_addr)->sin_addr, data, INET_ADDRSTRLEN); - } + if (family == AF_INET) + { + inet_ntop(AF_INET, &((sockaddr_in*) ip_addr)->sin_addr, data, + INET_ADDRSTRLEN); + } - return std::string { data }; + return std::string { data }; } -std::pair from_sockaddr_ex(const sockaddr *const ip_addr) { - char data[INET6_ADDRSTRLEN]; +std::pair from_sockaddr_ex( + const sockaddr *const ip_addr) +{ + char data[INET6_ADDRSTRLEN]; - auto family = ip_addr->sa_family; - std::uint16_t port; - if(family == AF_INET6) { - inet_ntop(AF_INET6, &((sockaddr_in6*)ip_addr)->sin6_addr, data, INET6_ADDRSTRLEN); - port = ((sockaddr_in6*)ip_addr)->sin6_port; - } + auto family = ip_addr->sa_family; + std::uint16_t port; + if (family == AF_INET6) + { + inet_ntop(AF_INET6, &((sockaddr_in6*) ip_addr)->sin6_addr, data, + INET6_ADDRSTRLEN); + port = ((sockaddr_in6*) ip_addr)->sin6_port; + } - if(family == AF_INET) { - inet_ntop(AF_INET, &((sockaddr_in*)ip_addr)->sin_addr, data, INET_ADDRSTRLEN); - port = ((sockaddr_in*)ip_addr)->sin_port; - } + if (family == AF_INET) + { + inet_ntop(AF_INET, &((sockaddr_in*) ip_addr)->sin_addr, data, + INET_ADDRSTRLEN); + port = ((sockaddr_in*) ip_addr)->sin_port; + } - return { port, std::string { data } }; + return + { port, std::string + { data}}; } -std::string get_mac_address(const std::string_view &address) { - auto ifaddrs = get_ifaddrs(); - for(auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) { - if(pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) { - std::ifstream mac_file("/sys/class/net/"s + pos->ifa_name + "/address"); - if(mac_file.good()) { - std::string mac_address; - std::getline(mac_file, mac_address); - return mac_address; - } - } - } - BOOST_LOG(warning) << "Unable to find MAC address for "sv << address; - return "00:00:00:00:00:00"s; +std::string get_mac_address(const std::string_view &address) +{ + auto ifaddrs = get_ifaddrs(); + for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) + { + if (pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) + { + std::ifstream mac_file( + "/sys/class/net/"s + pos->ifa_name + "/address"); + if (mac_file.good()) + { + std::string mac_address; + std::getline(mac_file, mac_address); + return mac_address; + } + } + } + BOOST_LOG(warning) + << "Unable to find MAC address for "sv << address; + return "00:00:00:00:00:00"s; } -void freeImage(XImage *p) { - XDestroyImage(p); +void freeImage(XImage *p) +{ + XDestroyImage(p); } -void freeX(XFixesCursorImage *p) { - XFree(p); +void freeX(XFixesCursorImage *p) +{ + XFree(p); } }