diff --git a/configure.ac b/configure.ac index e143d97c7..16a1407ef 100644 --- a/configure.ac +++ b/configure.ac @@ -1129,6 +1129,7 @@ RB_CHK_SYSHEADER(linux/perf_event.h, [LINUX_PERF_EVENT_H]) RB_CHK_SYSHEADER(linux/hw_breakpoint.h, [LINUX_HW_BREAKPOINT_H]) RB_CHK_SYSHEADER(linux/io_uring.h, [LINUX_IO_URING_H]) RB_CHK_SYSHEADER(linux/icmp.h, [LINUX_ICMP_H]) +RB_CHK_SYSHEADER(linux/input-event-codes.h, [LINUX_INPUT_EVENT_CODES_H]) dnl windows platform RB_CHK_SYSHEADER(windows.h, [WINDOWS_H]) diff --git a/include/ircd/beep.h b/include/ircd/beep.h new file mode 100644 index 000000000..37dd0cf56 --- /dev/null +++ b/include/ircd/beep.h @@ -0,0 +1,44 @@ +// Matrix Construct +// +// Copyright (C) Matrix Construct Developers, Authors & Contributors +// Copyright (C) 2016-2021 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#pragma once +#define HAVE_IRCD_BEEP_H + +/// pcspkr-event-spkr +namespace ircd +{ + struct beep; +} + +/// Transmits audible tone through the pcspkr for the object's duration. The +/// tone starts at construction and continues until terminated by destruction. +/// +class ircd::beep +{ + struct ctrl; + + static ctx::mutex mutex; + static conf::item path; + static conf::item debug; + + std::unique_lock lock; + fs::fd fd; + + public: + beep(const float tone = 2600.0f); + beep(beep &&) noexcept; + beep(const beep &) = delete; + beep &operator=(beep &&) noexcept; + beep &operator=(const beep &) = delete; + ~beep() noexcept; + + static bool available() noexcept; + static bool busy() noexcept; +}; diff --git a/include/ircd/ircd.h b/include/ircd/ircd.h index 56ad52158..3e28db33a 100644 --- a/include/ircd/ircd.h +++ b/include/ircd/ircd.h @@ -110,6 +110,7 @@ #include "net/net.h" #include "server/server.h" #include "png.h" +#include "beep.h" #include "magick.h" #include "resource/resource.h" #include "client.h" diff --git a/ircd/Makefile.am b/ircd/Makefile.am index 653018a26..d2ca160bc 100644 --- a/ircd/Makefile.am +++ b/ircd/Makefile.am @@ -229,6 +229,7 @@ endif if IMAGEMAGICK libircd_la_SOURCES += magick.cc endif +libircd_la_SOURCES += beep.cc libircd_la_SOURCES += png.cc if OPENCL libircd_la_SOURCES += cl.cc diff --git a/ircd/beep.cc b/ircd/beep.cc new file mode 100644 index 000000000..8899fbc1a --- /dev/null +++ b/ircd/beep.cc @@ -0,0 +1,158 @@ +// The Construct +// +// Copyright (C) The Construct Developers, Authors & Contributors +// Copyright (C) 2016-2021 Jason Volk +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice is present in all copies. The +// full license for this software is available in the LICENSE file. + +#if __has_include() + #include +#endif + +#ifndef EV_SND + #define EV_SND 0 +#endif + +#ifndef SND_TONE + #define SND_TONE 0 +#endif + +/// Event device file structure. +struct ircd::beep::ctrl +{ + struct timeval tv {0}; + uint16_t type {EV_SND}; + uint16_t code {SND_TONE}; + int32_t tone {0}; +}; + +decltype(ircd::beep::mutex) +ircd::beep::mutex; + +decltype(ircd::beep::path) +ircd::beep::path +{ + { "name", "ircd.beep.path" }, + { "default", "/dev/input/by-path/platform-pcspkr-event-spkr" }, +}; + +decltype(ircd::beep::debug) +ircd::beep::debug +{ + { "name", "ircd.beep.debug" }, + { "default", false }, +}; + +/// Is another ircd::ctx currently beeping? +bool +ircd::beep::busy() +noexcept +{ + return mutex.locked(); +} + +/// Is beeping at all possible for this platform? +bool +ircd::beep::available() +noexcept try +{ + return path && fs::exists(path); +} +catch(const std::exception &e) +{ + log::derror + { + "Failed to detect PC Speaker event availability :%s", + e.what() + }; + + return false; +} + +// +// beep::beep +// + +ircd::beep::beep(const float tone) +try +:lock +{ + tone > 0.0f? + std::unique_lock{mutex}: + std::unique_lock{mutex, std::defer_lock} +} +,fd +{ + tone > 0.0f? + fs::fd{string_view{path}, std::ios::out}: + fs::fd{-1} +} +{ + if(!fd) + return; + + beep::ctrl c; + c.tone = tone; + syscall(::write, int(fd), &c, sizeof(c)); + + if(debug) + log::debug + { + "PC Speaker audible tone active @ %-1.1f Hz", + tone, + }; +} +catch(const std::exception &e) +{ + log::error + { + "Failed to activate audible alarm :%s", + e.what(), + }; + + throw; +} + +ircd::beep::beep(beep &&other) +noexcept +:lock{std::move(other.lock)} +,fd{std::move(other.fd)} +{ +} + +ircd::beep & +ircd::beep::operator=(beep &&other) +noexcept +{ + this->~beep(); + lock = std::move(other.lock); + fd = std::move(other.fd); + return *this; +} + +ircd::beep::~beep() +noexcept try +{ + if(!fd) + return; + + assert(mutex.locked()); + assert(this->lock.owns_lock()); + + beep::ctrl c; + c.tone = 0; + syscall(::write, int(fd), &c, sizeof(c)); +} +catch(const std::exception &e) +{ + log::derror + { + "Failed to clear pcspkr event (%p)", + this, + }; + + return; +} diff --git a/modules/console.cc b/modules/console.cc index 47abb5776..1d4ad6b0e 100644 --- a/modules/console.cc +++ b/modules/console.cc @@ -619,6 +619,33 @@ console_cmd__sync(opt &out, const string_view &line) return true; } +bool +console_cmd__beep(opt &out, const string_view &line) +{ + const params param{line, " ", + { + "frequency", "duration" + }}; + + const auto tone + { + param.at("frequency", 2600.0f) + }; + + const auto duration + { + param.at("duration", 250ms) + }; + + beep beep + { + tone + }; + + ctx::sleep(duration); + return true; +} + // // log //