diff options
-rw-r--r-- | plugins/link/CMakeLists.txt | 19 | ||||
-rw-r--r-- | plugins/link/LinkedMem.h | 58 | ||||
-rw-r--r-- | plugins/link/link-posix.cpp | 189 | ||||
-rw-r--r-- | plugins/link/link.cpp | 326 |
4 files changed, 264 insertions, 328 deletions
diff --git a/plugins/link/CMakeLists.txt b/plugins/link/CMakeLists.txt index feb5e2c27..146657f89 100644 --- a/plugins/link/CMakeLists.txt +++ b/plugins/link/CMakeLists.txt @@ -3,15 +3,14 @@ # that can be found in the LICENSE file at the root of the # Mumble source tree or at <https://www.mumble.info/LICENSE>. -add_library(link SHARED) +add_library(link SHARED + "link.cpp" + "SharedMemory.cpp" +) -if(WIN32) - target_sources(link PRIVATE "link.cpp") -elseif(UNIX) - target_sources(link PRIVATE "link-posix.cpp") - - if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - find_library(LIB_RT "rt") - target_link_libraries(link PRIVATE ${LIB_RT}) - endif() +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + find_library(LIB_RT "rt") + target_link_libraries(link PRIVATE ${LIB_RT}) endif() + +target_include_directories(link PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/plugins/link/LinkedMem.h b/plugins/link/LinkedMem.h new file mode 100644 index 000000000..552867fd8 --- /dev/null +++ b/plugins/link/LinkedMem.h @@ -0,0 +1,58 @@ +// Copyright 2021 The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at <https://www.mumble.info/LICENSE>. + +#ifndef MUMBLE_PLUGINS_LINK_LINKEDMEM_H_ +#define MUMBLE_PLUGINS_LINK_LINKEDMEM_H_ + +#ifdef _WIN32 +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include "windows.h" +#else +# include <cstdint> +# include <cstdio> + +# include <unistd.h> +#endif + +struct LinkedMem { +#ifdef _WIN32 + UINT32 uiVersion; + DWORD uiTick; +#else + uint32_t uiVersion; + uint32_t uiTick; +#endif + float fAvatarPosition[3]; + float fAvatarFront[3]; + float fAvatarTop[3]; + wchar_t name[256]; + float fCameraPosition[3]; + float fCameraFront[3]; + float fCameraTop[3]; + wchar_t identity[256]; +#ifdef _WIN32 + UINT32 context_len; +#else + uint32_t context_len; +#endif + unsigned char context[256]; + wchar_t description[2048]; +}; + +static const char *getLinkedMemoryName() { +#ifdef _WIN32 + return "MumbleLink"; +#else + static char name[256] = {}; + + snprintf(name, 256, "/MumbleLink.%d", getuid()); + + return name; +#endif +} + +#endif // MUMBLE_PLUGINS_LINK_LINKEDMEM_H_ diff --git a/plugins/link/link-posix.cpp b/plugins/link/link-posix.cpp deleted file mode 100644 index efa67c804..000000000 --- a/plugins/link/link-posix.cpp +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2008-2021 The Mumble Developers. All rights reserved. -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file at the root of the -// Mumble source tree or at <https://www.mumble.info/LICENSE>. - -#define MUMBLE_ALLOW_DEPRECATED_LEGACY_PLUGIN_API -#include "mumble_legacy_plugin.h" - -#include <stdint.h> -#include <stdio.h> -#include <wchar.h> - -#include <fcntl.h> -#include <string.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> - -static std::wstring wsPluginName(L"Link"); -static std::wstring wsDescription; -static char memname[256]; - -struct LinkedMem { - uint32_t uiVersion; - uint32_t ui32count; - float fAvatarPosition[3]; - float fAvatarFront[3]; - float fAvatarTop[3]; - wchar_t name[256]; - float fCameraPosition[3]; - float fCameraFront[3]; - float fCameraTop[3]; - wchar_t identity[256]; - uint32_t context_len; - unsigned char context[256]; - wchar_t description[2048]; -}; - -/// Non-monotonic tick count in ms resolution -static int64_t GetTickCount() { - struct timeval tv; - gettimeofday(&tv, nullptr); - - return tv.tv_usec / 1000 + tv.tv_sec * 1000; -} - -#define lm_invalid reinterpret_cast< struct LinkedMem * >(-1) -static struct LinkedMem *lm = lm_invalid; -static int shmfd = -1; - -static int64_t last_tick = 0; -static uint32_t last_count = 0; - -static void unlock() { - lm->ui32count = last_count = 0; - lm->uiVersion = 0; - lm->name[0] = 0; - wsPluginName.assign(L"Link"); - wsDescription.clear(); -} - -static int trylock() { - if (lm == lm_invalid) - return false; - - if ((lm->uiVersion == 1) || (lm->uiVersion == 2)) { - if (lm->ui32count != last_count) { - last_tick = GetTickCount(); - last_count = lm->ui32count; - - wchar_t buff[2048]; - - if (lm->name[0]) { - wcsncpy(buff, lm->name, 256); - buff[255] = 0; - wsPluginName.assign(buff); - } - if (lm->description[0]) { - wcsncpy(buff, lm->description, 2048); - buff[2047] = 0; - wsDescription.assign(buff); - } - return true; - } - } - return false; -} - -static const std::wstring longdesc() { - return wsDescription; -} - -static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, - float *camera_top, std::string &context, std::wstring &identity) { - if (lm->ui32count != last_count) { - last_tick = GetTickCount(); - last_count = lm->ui32count; - } else if ((GetTickCount() - last_tick) > 5000) - return false; - - if ((lm->uiVersion != 1) && (lm->uiVersion != 2)) - return false; - - for (int i = 0; i < 3; ++i) { - avatar_pos[i] = lm->fAvatarPosition[i]; - avatar_front[i] = lm->fAvatarFront[i]; - avatar_top[i] = lm->fAvatarTop[i]; - } - - if (lm->uiVersion == 2) { - for (int i = 0; i < 3; ++i) { - camera_pos[i] = lm->fCameraPosition[i]; - camera_front[i] = lm->fCameraFront[i]; - camera_top[i] = lm->fCameraTop[i]; - } - - if (lm->context_len > 255) - lm->context_len = 255; - lm->identity[255] = 0; - - context.assign(reinterpret_cast< const char * >(lm->context), lm->context_len); - identity.assign(lm->identity); - } else { - for (int i = 0; i < 3; ++i) { - camera_pos[i] = lm->fAvatarPosition[i]; - camera_front[i] = lm->fAvatarFront[i]; - camera_top[i] = lm->fAvatarTop[i]; - } - context.clear(); - identity.clear(); - } - - return true; -} - -__attribute__((constructor)) static void load_plugin() { - bool bCreated = false; - - snprintf(memname, 256, "/MumbleLink.%d", getuid()); - - shmfd = shm_open(memname, O_RDWR, S_IRUSR | S_IWUSR); - if (shmfd < 0) { - bCreated = true; - shmfd = shm_open(memname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - } - - if (shmfd < 0) { - fprintf(stderr, "Mumble Link plugin: error creating shared memory\n"); - return; - } - - if (bCreated) { - if (ftruncate(shmfd, sizeof(struct LinkedMem)) != 0) { - fprintf(stderr, "Mumble Link plugin: failed to resize shared memory\n"); - close(shmfd); - shmfd = -1; - return; - } - } - - lm = static_cast< struct LinkedMem * >( - mmap(nullptr, sizeof(struct LinkedMem), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0)); - - if ((lm != lm_invalid) && bCreated) - memset(lm, 0, sizeof(struct LinkedMem)); -} - -__attribute__((destructor)) static void unload_plugin() { - if (lm != lm_invalid) - munmap(lm, sizeof(struct LinkedMem)); - - if (shmfd > -1) - close(shmfd); - - shm_unlink(memname); -} - -static std::wstring description(L"Link v1.2.0"); - -static MumblePlugin linkplug = { - MUMBLE_PLUGIN_MAGIC, description, wsPluginName, nullptr, nullptr, trylock, unlock, longdesc, fetch -}; - -extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin *getMumblePlugin() { - return &linkplug; -} diff --git a/plugins/link/link.cpp b/plugins/link/link.cpp index c51bfcb60..908e914d5 100644 --- a/plugins/link/link.cpp +++ b/plugins/link/link.cpp @@ -1,175 +1,243 @@ -// Copyright 2007-2021 The Mumble Developers. All rights reserved. +// Copyright 2008-2021 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at <https://www.mumble.info/LICENSE>. -#ifndef QT_NO_DEBUG -# include <stdio.h> -# include <stdlib.h> -#endif -#include <windows.h> -#include <math.h> - -#define MUMBLE_ALLOW_DEPRECATED_LEGACY_PLUGIN_API -#include "mumble_legacy_plugin.h" - -static std::wstring wsPluginName; -static std::wstring wsDescription; - -struct LinkedMem { - UINT32 uiVersion; - DWORD dwcount; - float fAvatarPosition[3]; - float fAvatarFront[3]; - float fAvatarTop[3]; - wchar_t name[256]; - float fCameraPosition[3]; - float fCameraFront[3]; - float fCameraTop[3]; - wchar_t identity[256]; - UINT32 context_len; - unsigned char context[256]; - wchar_t description[2048]; -}; - -static void about(void *h) { - ::MessageBox(reinterpret_cast< HWND >(h), L"Reads audio position information from linked game", - L"Mumble Link Plugin", MB_OK); +#include <chrono> +#include <codecvt> +#include <cstdint> +#include <cstring> +#include <iostream> +#include <locale> +#include <string> + +#include "LinkedMem.h" +#include "MumbleAPI_v_1_0_x.h" +#include "MumblePlugin_v_1_1_x.h" +#include "SharedMemory.h" + +#define UNUSED(x) (void) x + + +constexpr const char *defaultName = "Link"; +constexpr const char *defaultDescription = "Reads positional data from a linked game/software"; + +std::string pluginName(defaultName); +std::string applicationName; +std::string pluginDescription(defaultDescription); +std::string pluginContext; +std::string pluginIdentity; + +SharedMemory sharedMem; +LinkedMem *lm = nullptr; + +std::uint32_t last_tick = 0; +std::int64_t last_tick_time = 0; + +/** + * @returns Time in ms since Epoch + */ +static std::uint64_t getTimeSinceEpoch() { + return std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1); +} + +mumble_error_t mumble_init(mumble_plugin_id_t id) { + UNUSED(id); + + lm = static_cast< LinkedMem * >(sharedMem.mapMemory(getLinkedMemoryName(), sizeof(LinkedMem))); + + if (!lm) { + std::cerr << "Link plugin: Failed to setup shared memory: " << sharedMem.lastError() << std::endl; + + return MUMBLE_EC_INTERNAL_ERROR; + } + + return MUMBLE_STATUS_OK; +} + +void mumble_shutdown() { + sharedMem.close(); +} + +MumbleStringWrapper mumble_getName() { + MumbleStringWrapper wrapper; + wrapper.data = pluginName.c_str(); + wrapper.size = pluginName.size(); + wrapper.needsReleasing = false; + + return wrapper; +} + +mumble_version_t mumble_getAPIVersion() { + return MUMBLE_PLUGIN_API_VERSION; +} + +void mumble_registerAPIFunctions(void *apiStruct) { + UNUSED(apiStruct); +} + +void mumble_releaseResource(const void *pointer) { + // This function should never be called + UNUSED(pointer); + + std::terminate(); +} + +mumble_version_t mumble_getVersion() { + return { 1, 3, 0 }; +} + +MumbleStringWrapper mumble_getAuthor() { + static const char *author = "Mumble Developers"; + + MumbleStringWrapper wrapper; + wrapper.data = author; + wrapper.size = std::strlen(author); + wrapper.needsReleasing = false; + + return wrapper; +} + +MumbleStringWrapper mumble_getDescription() { + MumbleStringWrapper wrapper; + wrapper.data = pluginDescription.c_str(); + wrapper.size = pluginDescription.size(); + wrapper.needsReleasing = false; + + return wrapper; } -static HANDLE hMapObject = nullptr; -static LinkedMem *lm = nullptr; -static DWORD last_count = 0; -static DWORD last_tick = 0; - -static void unlock() { - lm->dwcount = last_count = 0; - lm->uiVersion = 0; - lm->name[0] = 0; - wsPluginName.assign(L"Link"); - wsDescription.clear(); +uint32_t mumble_getFeatures() { + return MUMBLE_FEATURE_POSITIONAL; } -static int trylock() { +uint8_t mumble_initPositionalData(const char *const *programNames, const uint64_t *programPIDs, size_t programCount) { + UNUSED(programNames); + UNUSED(programPIDs); + UNUSED(programCount); + + if (!lm) { + return MUMBLE_PDEC_ERROR_TEMP; + } + if ((lm->uiVersion == 1) || (lm->uiVersion == 2)) { - if (lm->dwcount != last_count) { - last_count = lm->dwcount; - last_tick = GetTickCount(); + if (lm->uiTick != last_tick) { + last_tick = lm->uiTick; + last_tick_time = getTimeSinceEpoch(); - errno_t err = 0; wchar_t buff[2048]; if (lm->name[0]) { - err = wcscpy_s(buff, 256, lm->name); - if (!err) - wsPluginName.assign(buff); - } - if (!err && lm->description[0]) { - err = wcscpy_s(buff, 2048, lm->description); - if (!err) - wsDescription.assign(buff); + wcsncpy(buff, lm->name, 256); + buff[255] = 0; + applicationName = std::wstring_convert< std::codecvt_utf8< wchar_t > >().to_bytes(buff); + + // Call the plugin itself "Link (<whatever>)" + pluginName += " (" + applicationName + ")"; } - if (err) { - wsPluginName.assign(L"Link"); - wsDescription.clear(); - return false; + + if (lm->description[0]) { + wcsncpy(buff, lm->description, 2048); + buff[2047] = 0; + pluginDescription = std::wstring_convert< std::codecvt_utf8< wchar_t > >().to_bytes(buff); } - return true; + + return MUMBLE_PDEC_OK; } } - return false; -} + return MUMBLE_PDEC_ERROR_TEMP; +} -static int fetch(float *avatar_pos, float *avatar_front, float *avatar_top, float *camera_pos, float *camera_front, - float *camera_top, std::string &context, std::wstring &identity) { - if (lm->dwcount != last_count) { - last_count = lm->dwcount; - last_tick = GetTickCount(); - } else if ((GetTickCount() - last_tick) > 5000) +#define SET_TO_ZERO(name) \ + name[0] = 0.0f; \ + name[1] = 0.0f; \ + name[2] = 0.0f +bool mumble_fetchPositionalData(float *avatarPos, float *avatarDir, float *avatarAxis, float *cameraPos, + float *cameraDir, float *cameraAxis, const char **context, const char **identity) { + SET_TO_ZERO(avatarPos); + SET_TO_ZERO(avatarDir); + SET_TO_ZERO(avatarAxis); + SET_TO_ZERO(cameraPos); + SET_TO_ZERO(cameraDir); + SET_TO_ZERO(cameraAxis); + + if (lm->uiTick != last_tick) { + last_tick = lm->uiTick; + last_tick_time = getTimeSinceEpoch(); + } else if ((getTimeSinceEpoch() - last_tick_time) > 5000) { return false; + } - if ((lm->uiVersion != 1) && (lm->uiVersion != 2)) + if ((lm->uiVersion != 1) && (lm->uiVersion != 2)) { return false; + } for (int i = 0; i < 3; ++i) { - avatar_pos[i] = lm->fAvatarPosition[i]; - avatar_front[i] = lm->fAvatarFront[i]; - avatar_top[i] = lm->fAvatarTop[i]; + avatarPos[i] = lm->fAvatarPosition[i]; + avatarDir[i] = lm->fAvatarFront[i]; + avatarAxis[i] = lm->fAvatarTop[i]; } if (lm->uiVersion == 2) { for (int i = 0; i < 3; ++i) { - camera_pos[i] = lm->fCameraPosition[i]; - camera_front[i] = lm->fCameraFront[i]; - camera_top[i] = lm->fCameraTop[i]; + cameraPos[i] = lm->fCameraPosition[i]; + cameraDir[i] = lm->fCameraFront[i]; + cameraAxis[i] = lm->fCameraTop[i]; } - if (lm->context_len > 255) + if (lm->context_len > 255) { lm->context_len = 255; + } lm->identity[255] = 0; - context.assign(reinterpret_cast< const char * >(lm->context), lm->context_len); - identity.assign(lm->identity); + pluginContext.assign(reinterpret_cast< const char * >(lm->context), lm->context_len); + pluginIdentity = std::wstring_convert< std::codecvt_utf8< wchar_t > >().to_bytes(lm->identity); } else { for (int i = 0; i < 3; ++i) { - camera_pos[i] = lm->fAvatarPosition[i]; - camera_front[i] = lm->fAvatarFront[i]; - camera_top[i] = lm->fAvatarTop[i]; + cameraPos[i] = lm->fAvatarPosition[i]; + cameraDir[i] = lm->fAvatarFront[i]; + cameraAxis[i] = lm->fAvatarTop[i]; } - context.clear(); - identity.clear(); + + pluginContext.clear(); + pluginIdentity.clear(); } - return true; -} + *context = pluginContext.c_str(); + *identity = pluginIdentity.c_str(); -static const std::wstring getdesc() { - return wsDescription; + return true; } -BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID) { - bool bCreated = false; - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - wsPluginName.assign(L"Link"); - hMapObject = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink"); - if (!hMapObject) { - hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, sizeof(LinkedMem), - L"MumbleLink"); - bCreated = true; - if (!hMapObject) - return false; - } - lm = static_cast< LinkedMem * >(MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, 0)); - if (!lm) { - CloseHandle(hMapObject); - hMapObject = nullptr; - return false; - } - if (bCreated) - memset(lm, 0, sizeof(LinkedMem)); - break; - case DLL_PROCESS_DETACH: - if (lm) { - UnmapViewOfFile(lm); - lm = nullptr; - } - if (hMapObject) { - CloseHandle(hMapObject); - hMapObject = nullptr; - } - break; +#undef SET_TO_ZERO + +void mumble_shutdownPositionalData() { + if (!applicationName.empty()) { + // We know that pluginName is in the format "Link (<whatever>)" where <whatever> is the applicationName + pluginName.erase(pluginName.size() - applicationName.size() - 3, std::string::npos); + } else if (applicationName.size() != std::strlen(defaultName)) { + // This code part should actually never run, since we expect the pluginName to be modified in the described way + // as soon as applicationName is defined. + pluginName.clear(); + pluginName.append(defaultName); } - return true; -} -static std::wstring description(L"Link v1.2.0"); + applicationName.clear(); + pluginDescription = std::string(defaultDescription); + pluginContext.clear(); + pluginIdentity.clear(); + + lm->uiTick = last_tick = 0; + lm->uiVersion = 0; + lm->name[0] = 0; +} -static MumblePlugin linkplug = { - MUMBLE_PLUGIN_MAGIC, description, wsPluginName, about, nullptr, trylock, unlock, getdesc, fetch -}; +MumbleStringWrapper mumble_getPositionalDataContextPrefix() { + MumbleStringWrapper wrapper; + wrapper.data = applicationName.c_str(); + wrapper.size = applicationName.size(); + wrapper.needsReleasing = false; -extern "C" MUMBLE_PLUGIN_EXPORT MumblePlugin *getMumblePlugin() { - return &linkplug; + return wrapper; } |