226 lines
11 KiB
C++
226 lines
11 KiB
C++
// Copyright 2021-2023 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_MUMBLE_API_H_
|
|
#define MUMBLE_MUMBLE_API_H_
|
|
|
|
// In here Mumble API structs for all versions are defined
|
|
#include "MumbleAPI_structs.h"
|
|
|
|
#include <atomic>
|
|
#include <functional>
|
|
#include <future>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <unordered_map>
|
|
|
|
#include <QObject>
|
|
|
|
namespace API {
|
|
|
|
class APIPromise {
|
|
public:
|
|
using lock_guard_t = std::unique_lock< std::recursive_mutex >;
|
|
|
|
APIPromise() = default;
|
|
|
|
void set_value(mumble_error_t value);
|
|
|
|
std::future< mumble_error_t > get_future();
|
|
|
|
lock_guard_t lock();
|
|
|
|
bool isCancelled() const;
|
|
void cancel();
|
|
|
|
protected:
|
|
std::promise< mumble_error_t > m_promise;
|
|
mutable std::recursive_mutex m_lock;
|
|
bool m_cancelled = false;
|
|
};
|
|
|
|
using api_future_t = std::future< mumble_error_t >;
|
|
using api_promise_t = APIPromise;
|
|
|
|
/// A "curator" that will keep track of allocated resources and how to delete them
|
|
struct MumbleAPICurator {
|
|
struct Entry {
|
|
/// The function used to delete the corresponding pointer
|
|
std::function< void(const void *) > m_deleter;
|
|
/// The ID of the plugin the resource pointed at was allocated for
|
|
mumble_plugin_id_t m_pluginID;
|
|
/// The name of the API function the resource pointed to was allocated in
|
|
/// NOTE: This must only ever be a pointer to a String literal.
|
|
const char *m_sourceFunctionName;
|
|
};
|
|
|
|
std::unordered_map< const void *, Entry > m_entries;
|
|
|
|
~MumbleAPICurator();
|
|
};
|
|
|
|
/// This object contains the actual API implementation. It also takes care of synchronizing API calls
|
|
/// with Mumble's main thread so that plugins can call them from an arbitrary thread without causing
|
|
/// issues.
|
|
/// This class is a singleton as a way to be able to write C function wrappers for the member functions
|
|
/// that are needed for passing to the plugins.
|
|
class MumbleAPI : public QObject {
|
|
Q_OBJECT
|
|
Q_DISABLE_COPY(MumbleAPI)
|
|
|
|
public:
|
|
static MumbleAPI &get();
|
|
|
|
public slots:
|
|
// The description of the functions is provided in MumbleAPI.h
|
|
|
|
// Note that every slot is synchronized and is therefore guaranteed to be executed in the main
|
|
// thread. For the synchronization strategy see below.
|
|
void freeMemory_v_1_0_x(mumble_plugin_id_t callerID, const void *ptr, std::shared_ptr< api_promise_t > promise);
|
|
void getActiveServerConnection_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t *connection,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void isConnectionSynchronized_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
|
|
bool *synchronized, std::shared_ptr< api_promise_t > promise);
|
|
void getLocalUserID_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t *userID,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getUserName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
|
|
const char **name, std::shared_ptr< api_promise_t > promise);
|
|
void getChannelName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
|
|
mumble_channelid_t channelID, const char **name,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getAllUsers_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t **users,
|
|
std::size_t *userCount, std::shared_ptr< api_promise_t > promise);
|
|
void getAllChannels_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
|
|
mumble_channelid_t **channels, std::size_t *channelCount,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getChannelOfUser_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
|
|
mumble_channelid_t *channelID, std::shared_ptr< api_promise_t > promise);
|
|
void getUsersInChannel_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
|
|
mumble_channelid_t channelID, mumble_userid_t **users, std::size_t *userCount,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID, mumble_transmission_mode_t *transmissionMode,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void isUserLocallyMuted_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
|
|
bool *muted, std::shared_ptr< api_promise_t > promise);
|
|
void isLocalUserMuted_v_1_0_x(mumble_plugin_id_t callerID, bool *muted, std::shared_ptr< api_promise_t > promise);
|
|
void isLocalUserDeafened_v_1_0_x(mumble_plugin_id_t callerID, bool *deafened,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getUserHash_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
|
|
const char **hash, std::shared_ptr< api_promise_t > promise);
|
|
void getServerHash_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char **hash,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void requestLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID,
|
|
mumble_transmission_mode_t transmissionMode,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getUserComment_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
|
|
const char **comment, std::shared_ptr< api_promise_t > promise);
|
|
void getChannelDescription_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
|
|
mumble_channelid_t channelID, const char **description,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void requestUserMove_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
|
|
mumble_channelid_t channelID, const char *password,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void requestMicrophoneActivationOverwrite_v_1_0_x(mumble_plugin_id_t callerID, bool activate,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void requestLocalMute_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
|
|
bool muted, std::shared_ptr< api_promise_t > promise);
|
|
void requestLocalUserMute_v_1_0_x(mumble_plugin_id_t callerID, bool muted,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void requestLocalUserDeaf_v_1_0_x(mumble_plugin_id_t callerID, bool deafened,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void requestSetLocalUserComment_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
|
|
const char *comment, std::shared_ptr< api_promise_t > promise);
|
|
void findUserByName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char *userName,
|
|
mumble_userid_t *userID, std::shared_ptr< api_promise_t > promise);
|
|
void findChannelByName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char *channelName,
|
|
mumble_channelid_t *channelID, std::shared_ptr< api_promise_t > promise);
|
|
void getMumbleSetting_bool_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, bool *outValue,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getMumbleSetting_int_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, int64_t *outValue,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getMumbleSetting_double_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, double *outValue,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void getMumbleSetting_string_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, const char **outValue,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void setMumbleSetting_bool_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, bool value,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void setMumbleSetting_int_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, int64_t value,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void setMumbleSetting_double_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, double value,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void setMumbleSetting_string_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, const char *value,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void sendData_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const mumble_userid_t *users,
|
|
std::size_t userCount, const uint8_t *data, std::size_t dataLength, const char *dataID,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void log_v_1_0_x(mumble_plugin_id_t callerID, const char *message, std::shared_ptr< api_promise_t > promise);
|
|
void playSample_v_1_0_x(mumble_plugin_id_t callerID, const char *samplePath,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
void playSample_v_1_2_x(mumble_plugin_id_t callerID, const char *samplePath, float volume,
|
|
std::shared_ptr< api_promise_t > promise);
|
|
|
|
|
|
private:
|
|
MumbleAPI();
|
|
|
|
MumbleAPICurator m_curator;
|
|
};
|
|
|
|
/// @returns The Mumble API struct (v1.0.x)
|
|
MumbleAPI_v_1_0_x getMumbleAPI_v_1_0_x();
|
|
|
|
/// @returns The Mumble API struct (v1.2.x)
|
|
MumbleAPI_v_1_2_x getMumbleAPI_v_1_2_x();
|
|
|
|
/// Converts from the Qt key-encoding to the API's key encoding.
|
|
///
|
|
/// @param keyCode The Qt key-code that shall be converted
|
|
/// @returns The converted key code or KC_INVALID if conversion failed
|
|
mumble_keycode_t qtKeyCodeToAPIKeyCode(unsigned int keyCode);
|
|
|
|
/// A class holding non-permanent data set by plugins. Non-permanent means that this data
|
|
/// will not be stored between restarts.
|
|
/// All member field should be atomic in order to be thread-safe
|
|
class PluginData {
|
|
public:
|
|
/// Constructor
|
|
PluginData();
|
|
/// Destructor
|
|
~PluginData();
|
|
|
|
/// A flag indicating whether a plugin has requested the microphone to be permanently on (mirroring the
|
|
/// behaviour of the continuous transmission mode.
|
|
std::atomic_bool overwriteMicrophoneActivation;
|
|
|
|
/// @returns A reference to the PluginData singleton
|
|
static PluginData &get();
|
|
}; // class PluginData
|
|
} // namespace API
|
|
|
|
|
|
// Declare the meta-types that we require in order for the API to work
|
|
Q_DECLARE_METATYPE(mumble_settings_key_t)
|
|
Q_DECLARE_METATYPE(mumble_settings_key_t *)
|
|
Q_DECLARE_METATYPE(mumble_transmission_mode_t)
|
|
Q_DECLARE_METATYPE(mumble_transmission_mode_t *)
|
|
Q_DECLARE_METATYPE(std::shared_ptr< API::api_promise_t >)
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
///////////// SYNCHRONIZATION STRATEGY ///////////////////////
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Every API function call checks whether it is being called from the main thread. If it is,
|
|
* it continues executing as usual. If it is not however, it uses Qt's signal/slot mechanism
|
|
* to schedule the respective function to be run in the main thread in the next iteration of
|
|
* the event loop.
|
|
* In order to synchronize with the calling thread, the return value (error code) of these
|
|
* functions is "returned" as a promise. Thus by accessing the exit code via the corresponding
|
|
* future, the calling thread is blocked until the function has been executed in the main thread
|
|
* (and thereby set the exit code once it is done allowing the calling thread to unblock).
|
|
*/
|
|
|
|
#endif
|