From 73e70184d10808dd286ea1de94b138d52f4ab0cd Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Thu, 15 Jun 2023 04:21:22 +0200 Subject: [PATCH 1/6] Add basic readme with instructions for custom pluginsdk dir. Refs #14. --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..8763c9a --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# TeamSpeak3 Plugin SDK for Golang + +This library allows developers to write plugins for the TeamSpeak3 client in +Go. + +Note that its current functionality is limited. A huge part has not been +implemented yet but this should be enough to interact with the chat or set up +automations. + +## Requirements + +- Go 1.18 or newer (older versions have not been tested against). +- A working C compiler suite. +- Your own unpacked copy of [Version 24 the TeamSpeak3 Plugin SDK](https://github.com/TeamSpeak-Systems/ts3client-pluginsdk/tree/a39d50383b4a023941c31c08fe0c9766b149ed01). + To download it just click "Code" and then "Download ZIP" there. +- Having the `include/` directory exported as part of environment variable + `CGO_CPPFLAGS` (e.g. `-I/path/to/your/sdk/copy/include/`). From 091f3e03f05e2e0a69b6a5a3d9d173755a9eb380 Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Thu, 15 Jun 2023 04:26:37 +0200 Subject: [PATCH 2/6] Remove pluginsdk/ from source tree. Refs #14. --- plugin_definitions.go | 2 +- pluginsdk/.gitignore | 2 - pluginsdk/.travis.yml | 2 - pluginsdk/Makefile | 16 - pluginsdk/README.md | 19 - pluginsdk/docs/client.html | 8 - pluginsdk/docs/client.pdf | Bin 396229 -> 0 bytes pluginsdk/docs/client_html/ar01s01.html | 1 - pluginsdk/docs/client_html/ar01s02.html | 1 - pluginsdk/docs/client_html/ar01s03.html | 1 - pluginsdk/docs/client_html/ar01s04.html | 21 - pluginsdk/docs/client_html/ar01s05.html | 33 - pluginsdk/docs/client_html/ar01s06.html | 22 - pluginsdk/docs/client_html/ar01s07.html | 3 - pluginsdk/docs/client_html/ar01s08.html | 5 - pluginsdk/docs/client_html/ar01s09.html | 62 - pluginsdk/docs/client_html/ar01s10.html | 5 - pluginsdk/docs/client_html/ar01s11.html | 27 - pluginsdk/docs/client_html/ar01s12.html | 14 - pluginsdk/docs/client_html/ar01s13.html | 9 - pluginsdk/docs/client_html/ar01s13s02.html | 69 - pluginsdk/docs/client_html/ar01s13s03.html | 10 - pluginsdk/docs/client_html/ar01s13s04.html | 23 - pluginsdk/docs/client_html/ar01s13s05.html | 44 - pluginsdk/docs/client_html/ar01s13s06.html | 1 - pluginsdk/docs/client_html/ar01s14.html | 3 - pluginsdk/docs/client_html/ar01s15.html | 13 - pluginsdk/docs/client_html/ar01s16.html | 9 - pluginsdk/docs/client_html/ar01s17.html | 32 - pluginsdk/docs/client_html/ar01s18.html | 19 - pluginsdk/docs/client_html/ar01s19.html | 13 - pluginsdk/docs/client_html/ar01s20.html | 16 - pluginsdk/docs/client_html/ar01s21.html | 41 - pluginsdk/docs/client_html/ar01s22.html | 143 -- pluginsdk/docs/client_html/ar01s22s02.html | 75 -- pluginsdk/docs/client_html/ar01s22s02s02.html | 7 - pluginsdk/docs/client_html/ar01s22s03.html | 49 - pluginsdk/docs/client_html/ar01s23.html | 27 - pluginsdk/docs/client_html/ar01s23s02.html | 36 - pluginsdk/docs/client_html/ar01s23s03.html | 6 - pluginsdk/docs/client_html/ar01s23s04.html | 6 - pluginsdk/docs/client_html/ar01s23s05.html | 1 - pluginsdk/docs/client_html/ar01s23s05s01.html | 15 - pluginsdk/docs/client_html/ar01s23s05s02.html | 8 - pluginsdk/docs/client_html/ar01s23s06.html | 14 - pluginsdk/docs/client_html/ar01s23s07.html | 28 - pluginsdk/docs/client_html/ar01s24.html | 13 - pluginsdk/docs/client_html/ar01s25.html | 24 - pluginsdk/docs/client_html/ar01s26.html | 3 - pluginsdk/docs/client_html/ar01s27.html | 19 - pluginsdk/docs/client_html/ar01s28.html | 14 - pluginsdk/docs/client_html/ar01s29.html | 95 -- pluginsdk/docs/client_html/ar01s30.html | 47 - pluginsdk/docs/client_html/images/caution.png | Bin 887 -> 0 bytes pluginsdk/docs/client_html/images/home.png | Bin 879 -> 0 bytes .../docs/client_html/images/important.png | Bin 887 -> 0 bytes pluginsdk/docs/client_html/images/logo.png | Bin 7194 -> 0 bytes pluginsdk/docs/client_html/images/next.png | Bin 681 -> 0 bytes pluginsdk/docs/client_html/images/note.png | Bin 815 -> 0 bytes pluginsdk/docs/client_html/images/prev.png | Bin 649 -> 0 bytes pluginsdk/docs/client_html/images/up.png | Bin 612 -> 0 bytes pluginsdk/docs/client_html/index.html | 5 - pluginsdk/docs/client_html/ix01.html | 1 - pluginsdk/docs/client_html/ts3doc.css | 50 - pluginsdk/include/plugin_definitions.h | 74 -- pluginsdk/include/teamlog/logtypes.h | 23 - .../teamspeak/clientlib_publicdefinitions.h | 25 - .../include/teamspeak/public_definitions.h | 392 ------ pluginsdk/include/teamspeak/public_errors.h | 194 --- .../include/teamspeak/public_errors_rare.h | 98 -- .../teamspeak/public_rare_definitions.h | 361 ----- pluginsdk/include/ts3_functions.h | 305 ----- pluginsdk/readme.txt | 23 - pluginsdk/src/icons/1.png | Bin 234 -> 0 bytes pluginsdk/src/icons/2.png | Bin 297 -> 0 bytes pluginsdk/src/icons/3.png | Bin 303 -> 0 bytes pluginsdk/src/icons/t.png | Bin 241 -> 0 bytes pluginsdk/src/plugin.c | 1169 ----------------- pluginsdk/src/plugin.h | 150 --- pluginsdk/src/test_plugin.sln | 22 - pluginsdk/src/test_plugin.vcxproj | 99 -- pluginsdk/src/test_plugin.vcxproj.filters | 53 - teamlog/logtypes.go | 2 +- teamspeak/clientlib_publicdefinitions.go | 2 +- teamspeak/public_definitions.go | 2 +- teamspeak/public_errors.go | 2 +- teamspeak/public_errors_rare.go | 2 +- teamspeak/public_rare_definitions.go | 2 +- ts3_functions.go | 2 +- ts3plugin.go | 2 - 90 files changed, 8 insertions(+), 4228 deletions(-) delete mode 100644 pluginsdk/.gitignore delete mode 100644 pluginsdk/.travis.yml delete mode 100644 pluginsdk/Makefile delete mode 100644 pluginsdk/README.md delete mode 100644 pluginsdk/docs/client.html delete mode 100644 pluginsdk/docs/client.pdf delete mode 100644 pluginsdk/docs/client_html/ar01s01.html delete mode 100644 pluginsdk/docs/client_html/ar01s02.html delete mode 100644 pluginsdk/docs/client_html/ar01s03.html delete mode 100644 pluginsdk/docs/client_html/ar01s04.html delete mode 100644 pluginsdk/docs/client_html/ar01s05.html delete mode 100644 pluginsdk/docs/client_html/ar01s06.html delete mode 100644 pluginsdk/docs/client_html/ar01s07.html delete mode 100644 pluginsdk/docs/client_html/ar01s08.html delete mode 100644 pluginsdk/docs/client_html/ar01s09.html delete mode 100644 pluginsdk/docs/client_html/ar01s10.html delete mode 100644 pluginsdk/docs/client_html/ar01s11.html delete mode 100644 pluginsdk/docs/client_html/ar01s12.html delete mode 100644 pluginsdk/docs/client_html/ar01s13.html delete mode 100644 pluginsdk/docs/client_html/ar01s13s02.html delete mode 100644 pluginsdk/docs/client_html/ar01s13s03.html delete mode 100644 pluginsdk/docs/client_html/ar01s13s04.html delete mode 100644 pluginsdk/docs/client_html/ar01s13s05.html delete mode 100644 pluginsdk/docs/client_html/ar01s13s06.html delete mode 100644 pluginsdk/docs/client_html/ar01s14.html delete mode 100644 pluginsdk/docs/client_html/ar01s15.html delete mode 100644 pluginsdk/docs/client_html/ar01s16.html delete mode 100644 pluginsdk/docs/client_html/ar01s17.html delete mode 100644 pluginsdk/docs/client_html/ar01s18.html delete mode 100644 pluginsdk/docs/client_html/ar01s19.html delete mode 100644 pluginsdk/docs/client_html/ar01s20.html delete mode 100644 pluginsdk/docs/client_html/ar01s21.html delete mode 100644 pluginsdk/docs/client_html/ar01s22.html delete mode 100644 pluginsdk/docs/client_html/ar01s22s02.html delete mode 100644 pluginsdk/docs/client_html/ar01s22s02s02.html delete mode 100644 pluginsdk/docs/client_html/ar01s22s03.html delete mode 100644 pluginsdk/docs/client_html/ar01s23.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s02.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s03.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s04.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s05.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s05s01.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s05s02.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s06.html delete mode 100644 pluginsdk/docs/client_html/ar01s23s07.html delete mode 100644 pluginsdk/docs/client_html/ar01s24.html delete mode 100644 pluginsdk/docs/client_html/ar01s25.html delete mode 100644 pluginsdk/docs/client_html/ar01s26.html delete mode 100644 pluginsdk/docs/client_html/ar01s27.html delete mode 100644 pluginsdk/docs/client_html/ar01s28.html delete mode 100644 pluginsdk/docs/client_html/ar01s29.html delete mode 100644 pluginsdk/docs/client_html/ar01s30.html delete mode 100644 pluginsdk/docs/client_html/images/caution.png delete mode 100644 pluginsdk/docs/client_html/images/home.png delete mode 100644 pluginsdk/docs/client_html/images/important.png delete mode 100644 pluginsdk/docs/client_html/images/logo.png delete mode 100644 pluginsdk/docs/client_html/images/next.png delete mode 100644 pluginsdk/docs/client_html/images/note.png delete mode 100644 pluginsdk/docs/client_html/images/prev.png delete mode 100644 pluginsdk/docs/client_html/images/up.png delete mode 100644 pluginsdk/docs/client_html/index.html delete mode 100644 pluginsdk/docs/client_html/ix01.html delete mode 100644 pluginsdk/docs/client_html/ts3doc.css delete mode 100644 pluginsdk/include/plugin_definitions.h delete mode 100755 pluginsdk/include/teamlog/logtypes.h delete mode 100644 pluginsdk/include/teamspeak/clientlib_publicdefinitions.h delete mode 100644 pluginsdk/include/teamspeak/public_definitions.h delete mode 100644 pluginsdk/include/teamspeak/public_errors.h delete mode 100644 pluginsdk/include/teamspeak/public_errors_rare.h delete mode 100644 pluginsdk/include/teamspeak/public_rare_definitions.h delete mode 100644 pluginsdk/include/ts3_functions.h delete mode 100644 pluginsdk/readme.txt delete mode 100644 pluginsdk/src/icons/1.png delete mode 100644 pluginsdk/src/icons/2.png delete mode 100644 pluginsdk/src/icons/3.png delete mode 100644 pluginsdk/src/icons/t.png delete mode 100644 pluginsdk/src/plugin.c delete mode 100644 pluginsdk/src/plugin.h delete mode 100644 pluginsdk/src/test_plugin.sln delete mode 100644 pluginsdk/src/test_plugin.vcxproj delete mode 100644 pluginsdk/src/test_plugin.vcxproj.filters diff --git a/plugin_definitions.go b/plugin_definitions.go index d375fb1..a4fb312 100644 --- a/plugin_definitions.go +++ b/plugin_definitions.go @@ -1,7 +1,7 @@ package ts3plugin /* -#cgo CFLAGS: -I./pluginsdk/include -I. +#cgo CFLAGS: -I. #include // uint types diff --git a/pluginsdk/.gitignore b/pluginsdk/.gitignore deleted file mode 100644 index 94f1119..0000000 --- a/pluginsdk/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.DS_Store -.vscode diff --git a/pluginsdk/.travis.yml b/pluginsdk/.travis.yml deleted file mode 100644 index 3393b24..0000000 --- a/pluginsdk/.travis.yml +++ /dev/null @@ -1,2 +0,0 @@ -language: C -script: make diff --git a/pluginsdk/Makefile b/pluginsdk/Makefile deleted file mode 100644 index 9a129ce..0000000 --- a/pluginsdk/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# -# Makefile to build TeamSpeak 3 Client Test Plugin -# - -CFLAGS = -c -O2 -Wall -fPIC - -all: test_plugin - -test_plugin: plugin.o - gcc -o test_plugin.so -shared plugin.o - -plugin.o: ./src/plugin.c - gcc -Iinclude src/plugin.c $(CFLAGS) - -clean: - rm -rf *.o test_plugin.so diff --git a/pluginsdk/README.md b/pluginsdk/README.md deleted file mode 100644 index 4dd0908..0000000 --- a/pluginsdk/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# TeamSpeak 3 Client Plugin SDK - -This is the official helper repository that contains example code and the SDK header files -required to create native plugins for the TeamSpeak 3 Client. - -## Getting Started - -It's strongly recommended to build upon the test plugin. Plugins are required to export some -special functions, which already exist in the test plugin. Optional functions may be removed -if not used. See code comments for details. - -For more information, please refer to the following pages: - -- [TeamSpeak Community Forums](https://forum.teamspeak.com) -- [TeamSpeak SDK Downloads](https://www.teamspeak.com/downloads#sdk) - -## Copyright - -Copyright © TeamSpeak Systems GmbH. All rights reserved. diff --git a/pluginsdk/docs/client.html b/pluginsdk/docs/client.html deleted file mode 100644 index 929a6a1..0000000 --- a/pluginsdk/docs/client.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - -

You will be automatically forwarded to the Client SDK manual.
Click on the link below if your browser does not support forwarding.

-

Client SDK manual

- - diff --git a/pluginsdk/docs/client.pdf b/pluginsdk/docs/client.pdf deleted file mode 100644 index 949ce38a62abdc777bd1aa5cc7b2149fd678d9d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 396229 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 diff --git a/pluginsdk/docs/client_html/ar01s02.html b/pluginsdk/docs/client_html/ar01s02.html deleted file mode 100644 index fc01461..0000000 --- a/pluginsdk/docs/client_html/ar01s02.html +++ /dev/null @@ -1 +0,0 @@ -System requirements

System requirements

For developing third-party clients with the TeamSpeak 3 Client Lib the following system requirements apply:

  • Windows

    Windows 7, 8, 8.1 (32- and 64-bit)

  • Mac OS X

    Mac OS X 10.6 and above

  • Linux

    Any recent Linux distribution with libstdc++ 6 (32- and 64-bit)

[Important]Important

The calling convention used in the functions exported by the shared TeamSpeak 3 SDK libaries is cdecl. You must not use another calling convention, like stdcall on Windows, when declaring function pointers to the TeamSpeak 3 SDK libraries. Otherwise stack corruption at runtime may occur.

diff --git a/pluginsdk/docs/client_html/ar01s03.html b/pluginsdk/docs/client_html/ar01s03.html deleted file mode 100644 index 71ff35c..0000000 --- a/pluginsdk/docs/client_html/ar01s03.html +++ /dev/null @@ -1 +0,0 @@ -Overview of header files

Overview of header files

The following header files are deployed to SDK developers:

  • clientlib.h

    Declares the function prototypes and callbacks for the communication between Client Lib and Client UI. While the Client UI makes function calls into the Client Lib using the declared prototypes, the Client Lib calls the Client UI via callbacks.

  • clientlib_publicdefinitions.h

    Defines various enums and structs used by the Client UI and Client Lib. These definitions are used by the functions and callbacks declared in clientlib.h

  • public_definitions.h

    Defines various enums and structs used by both client- and server-side.

  • public_sdk_definitions.h

    Enum definitions for filetransfer support.

  • public_errors.h

    Defines the error codes returned by every Client Lib function and onServerErrorEvent. Error codes are organized in several groups. The first byte of the error code defines the error group, the second the count within the group.

diff --git a/pluginsdk/docs/client_html/ar01s04.html b/pluginsdk/docs/client_html/ar01s04.html deleted file mode 100644 index c2184bb..0000000 --- a/pluginsdk/docs/client_html/ar01s04.html +++ /dev/null @@ -1,21 +0,0 @@ -Calling Client Lib functions

Calling Client Lib functions

Client Lib functions follow a common pattern. They always return an error code or ERROR_ok on success. If there is a result variable, it is always the last variable in the functions parameters list.

ERROR ts3client_FUNCNAME(arg1, arg2, ..., &result);

Result variables should only be accessed if the function returned ERROR_ok. Otherwise the state of the result variable is undefined.

In those cases where the result variable is a basic type (int, float etc.), the memory for the result variable has to be declared by the caller. Simply pass the address of the variable to the Client Lib function.

int result;
-
-if(ts3client_XXX(arg1, arg2, ..., &result) == ERROR_ok) {
-    /* Use result variable */
-} else {
-    /* Handle error, result variable is undefined */
-}

If the result variable is a pointer type (C strings, arrays etc.), the memory is allocated by the Client Lib function. In that case, the caller has to release the allocated memory later by using ts3client_freeMemory. It is important to only access and release the memory if the function returned ERROR_ok. Should the function return an error, the result variable is uninitialized, so freeing or accessing it could crash the application.

char* result;
-
-if(ts3client_XXX(arg1, arg2, ..., &result) == ERROR_ok) {
-    /* Use result variable */
-    ts3client_freeMemory(result);  /* Release result variable */
-} else {
-    /* Handle error, result variable is undefined. Do not access or release it. */
-}
[Note]Note

Client Lib functions are thread-safe. It is possible to access the Client Lib from several threads at the same time.

Return code

Client Lib functions that interact with the server take an additional parameter returnCode, which can be used to find out which action results in a later server error. If you pass a custom string as return code, the onServerErrorEvent callback will receive the same custom string in its returnCode parameter. If no error occured, onServerErrorEvent will indicate success py passing the error code ERROR_ok.

Pass NULL as returnCode if you do not need the feature. In this case, if no error occurs onServerErrorEvent will not be called.

An example, request moving a client:

ts3client_requestClientMove(scHandlerID, clientID, newChannelID, password, "MyClientMoveReturnCode");

If an error occurs, the onServerErrorEvent callback is called:

void my_onServerErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage,
-                           unsigned int error, const char* returnCode, const char* extraMessage) {
-    if(strcmp(returnCode, "MyClientMoveReturnCode")) == 0) {
-        /* We know this error is the reaction to above called function as we got the same returnCode */
-	if(error == ERROR_ok) {
-	    /* Success */
-	}
-}
diff --git a/pluginsdk/docs/client_html/ar01s05.html b/pluginsdk/docs/client_html/ar01s05.html deleted file mode 100644 index 350acdb..0000000 --- a/pluginsdk/docs/client_html/ar01s05.html +++ /dev/null @@ -1,33 +0,0 @@ -Initializing

Initializing

When starting the client, initialize the Client Lib with a call to -

unsigned int ts3client_initClientLib(functionPointers,  
 functionRarePointers,  
 usedLogTypes,  
 logFileFolder,  
 resourcesFolder); 
const struct ClientUIFunctions* functionPointers;
const struct ClientUIFunctionsRare* functionRarePointers;
int usedLogTypes;
const char* logFileFolder;
const char* resourcesFolder;
 

-

  • functionPointers

    Callback function pointers. See below.

  • functionRarePointers

    Unused by SDK, pass NULL.

  • usedLogTypes

    Defines the log output types. The Client Lib can output log messages (called by ts3client_logMessage) to a file (located in the logs directory relative to the client executable), to stdout or to user defined callbacks. If user callbacks are activated, the onUserLoggingMessageEvent event needs to be implemented.

    Available values are defined by the enum LogTypes (see public_definitions.h):

    enum LogTypes {
    -    LogType_NONE          = 0x0000,
    -    LogType_FILE          = 0x0001,
    -    LogType_CONSOLE       = 0x0002,
    -    LogType_USERLOGGING   = 0x0004,
    -    LogType_NO_NETLOGGING = 0x0008,
    -    LogType_DATABASE      = 0x0010,
    -};

    Multiple log types can be combined with a binary OR. If only LogType_NONE is used, local logging is disabled.

    [Note]Note

    Logging to console can slow down the application on Windows. Hence we do not recommend to log to the console on Windows other than in debug builds.

    [Note]Note

    LogType_NO_NETLOGGING is no longer used. Previously this controlled if the Client Lib would send warning, error and critical log entries to a webserver for analysis. As netlogging does not occur anymore, this flag has no effect anymore.

    LogType_DATABASE has no effect in the Client Lib, this is only used by the server.

  • logFileFolder

    If file logging is used, this defines the location where the logs are written to. Pass NULL for the default behaviour, which is to use a folder called logs in the current working directory.

    resourcesFolder

    Resource path pointing to the directory where the soundbackends folder is located. Required so your application finds the sound backend shared libraries. This should usually point to the root or bin directory of your application, depending where the soundbackends directory is located.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

[Note]Note

This function must not be called more than once.

The callback mechanism

The communication from Client Lib to Client UI takes place using callbacks. The Client UI has to define a series of function pointers using the struct ClientUIFunctions (see clientlib.h). These callbacks are used to forward any incoming server actions to the Client UI for further processing.

[Note]Note

All the clientlib callbacks are asynchronous, except for the sound callbacks which allow to directly manipulate the sound buffer.

A callback example in C:

static void my_onConnectStatusChangeEvent_Callback(uint64 serverConnectionHandlerID,
-                                                   int newStatus,
-                                                   int errorNumber) {
-    /* Implementation */
-}

C++ developers can also use static member functions for the callbacks.

Before calling ts3client_initClientLib, create an instance of struct ClientUIFunctions, initialize all function pointers with NULL and assign the structs function pointers to your callback functions: -

unsigned int error;
-
-/* Create struct */
-ClientUIFunctions clUIFuncs;
-
-/* Initialize all function pointers with NULL */
-memset(&clUIFuncs, 0, sizeof(struct ClientUIFunctions));
-
-/* Assign those function pointers you implemented */
-clUIFuncs.onConnectStatusChangeEvent = my_onConnectStatusChangeEvent_Callback;
-clUIFuncs.onNewChannelEvent          = my_onNewChannelEvent_Callback;
-(...)
-
-/* Initialize client lib with callback function pointers */
-error = ts3client_initClientLib(&clUIFuncs, NULL, LogType_FILE | LogType_CONSOLE);
-if(error != ERROR_ok) {
-    printf("Error initializing clientlib: %d\n", error);
-    (...)
-}
[Important]Important

As long as you initialize unimplemented callbacks with NULL, the Client Lib won't attempt to call those function pointers. However, if you leave unimplemented callbacks undefined, the Client Lib will crash when trying to calling them.

[Note]Note

All callbacks used in the SDK are found in the struct ClientUIFunctions (see public_definitions.h). Callbacks bundled in the struct ClientUIFunctionsRare are not used by the SDK. These callbacks were split in a separate structs to avoid polluting the SDK headers with code used only internally.

diff --git a/pluginsdk/docs/client_html/ar01s06.html b/pluginsdk/docs/client_html/ar01s06.html deleted file mode 100644 index 07329ee..0000000 --- a/pluginsdk/docs/client_html/ar01s06.html +++ /dev/null @@ -1,22 +0,0 @@ -Querying the library version

Querying the library version

The complete Client Lib version string can be queried with

unsigned int ts3client_getClientLibVersion(result); 
char** result;
 
  • result

    Address of a variable that receives the clientlib version string, encoded in UTF-8.

[Caution]Caution

The result string must be released using ts3client_freeMemory. If an error has occured, the result string is uninitialized and must not be released.


-

To get only the version number, which is a part of the complete version string, as numeric value: -

unsigned int ts3client_getClientLibVersionNumber(result); 
uint64* result;
 

-

  • result

    Address of a variable that receives the numeric clientlib version.

Both functions return ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

An example using ts3client_getClientLibVersion: -

unsigned int error;
-char* version;
-error = ts3client_getClientLibVersion(&version);
-if(error != ERROR_ok) {
-    printf("Error querying clientlib version: %d\n", error);
-    return;
-}
-printf("Client library version: %s\n", version);  /* Print version */
-ts3client_freeMemory(version);  /* Release string */

Example using ts3client_getClientLibVersionNumber: -

unsigned int error;
-uint64 version;
-error = ts3client_getClientLibVersionNumber(&version);
-if(error != ERROR_ok) {
-    printf("Error querying clientlib version number: %d\n", error);
-    return;
-}
-printf("Client library version number: %ld\n", version);  /* Print version */
diff --git a/pluginsdk/docs/client_html/ar01s07.html b/pluginsdk/docs/client_html/ar01s07.html deleted file mode 100644 index 5b8139d..0000000 --- a/pluginsdk/docs/client_html/ar01s07.html +++ /dev/null @@ -1,3 +0,0 @@ -Shutting down

Shutting down

Before exiting the client application, the Client Lib should be shut down with -

unsigned int ts3client_destroyClientLib(); 
 

-

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

Make sure to call this function after disconnecting from any TeamSpeak 3 servers. Any call to Client Lib functions after shutting down has undefined results.

diff --git a/pluginsdk/docs/client_html/ar01s08.html b/pluginsdk/docs/client_html/ar01s08.html deleted file mode 100644 index f669d70..0000000 --- a/pluginsdk/docs/client_html/ar01s08.html +++ /dev/null @@ -1,5 +0,0 @@ -Managing server connection handlers

Managing server connection handlers

Before connecting to a TeamSpeak 3 server, a new server connection handler needs to be spawned. Each handler is identified by a unique ID (usually called serverConnectionHandlerID). With one server connection handler a connection can be established and dropped multiple times, so for simply reconnecting to the same or another server no new handler needs to be spawned but existing ones can be reused. However, for using multiple connections simultaneously a new handler has to be spawned for each connection.

To create a new server connection handler and receive its ID, call -

unsigned int ts3client_spawnNewServerConnectionHandler(port,  
 result); 
int port;
uint64* result;
 

-

  • port

    Port the client should bind on. Specify zero to let the operating system chose any free port. In most cases passing zero is the best choice.

    If port is specified, the function return value should be checked for ERROR_unable_to_bind_network_port. Handle this error by switching to an alternative port until a "free" port is hit and the function returns ERROR_ok.

    [Caution]Caution

    Do not specify a non-zero value for port unless you absolutely need a specific port. Passing zero is the better way in most use cases.

  • result

    Address of a variable that receives the server connection handler ID.

To destroy a server connection handler, call -

unsigned int ts3client_destroyServerConnectionHandler(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler to destroy.

Both functions return ERROR_ok on success, otherwise an error code as defined in public_errors.h.

[Important]Important

Destroying invalidates the handler ID, so it must not be used anymore afterwards. Also do not destroy a server connection handler ID from within a callback.

diff --git a/pluginsdk/docs/client_html/ar01s09.html b/pluginsdk/docs/client_html/ar01s09.html deleted file mode 100644 index d673087..0000000 --- a/pluginsdk/docs/client_html/ar01s09.html +++ /dev/null @@ -1,62 +0,0 @@ -Connecting to a server

Connecting to a server

To connect to a server, a client application is required to request an identity from the Client Lib. This string should be requested only once and then locally stored in the applications configuration. The next time the application connects to a server, the identity should be read from the configuration and reused again. -

unsigned int ts3client_createIdentity(result); 
char** result;
 

-

  • result

    Address of a variable that receives the identity string, encoded in UTF-8.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error occured, the result string is uninitialized and must not be accessed.

[Caution]Caution

The result string must be released using ts3client_freeMemory. If an error has occured, the result string is uninitialized and must not be released.


-

Once a server connection handler has been spawned and an identity is available, connect to a TeamSpeak 3 server with -

unsigned int ts3client_startConnection(serverConnectionHandlerID,  
 identity,  
 ip,  
 port,  
 nickname,  
 defaultChannelArray,  
 defaultChannelPassword,  
 serverPassword); 
uint64 serverConnectionHandlerID;
const char* identity;
const char* ip;
unsigned int port;
const char* nickname;
const char** defaultChannelArray;
const char* defaultChannelPassword;
const char* serverPassword;
 

-

  • serverConnectionHandlerID

    Unique identifier for this server connection. Created with ts3client_spawnNewServerConnectionHandler

  • identity

    The clients identity. This string has to be created by calling ts3client_createIdentity. Please note an application should create the identity only once, store the string locally and reuse it for future connections.

  • ip

    Hostname or IP of the TeamSpeak 3 server.

    If you pass a hostname instead of an IP, the Client Lib will try to resolve it to an IP, but the function may block for an unusually long period of time while resolving is taking place. If you are relying on the function to return quickly, we recommend to resolve the hostname yourself (e.g. asynchronously) and then call ts3client_startConnection with the IP instead of the hostname.

  • port

    UDP port of the TeamSpeak 3 server, by default 9987. TeamSpeak 3 uses UDP. Support for TCP might be added in the future.

  • nickname

    On login, the client attempts to take this nickname on the connected server. Note this is not necessarily the actually assigned nickname, as the server can modifiy the nickname ("gandalf_1" instead the requested "gandalf") or refuse blocked names.

  • defaultChannelArray

    String array defining the path to a channel on the TeamSpeak 3 server. If the channel exists and the user has sufficient rights and supplies the correct password if required, the channel will be joined on login.

    To define the path to a subchannel of arbitrary level, create an array of channel names detailing the position of the default channel (e.g. "grandparent", "parent", "mydefault", ""). The array is terminated with a empty string.

    Pass NULL to join the servers default channel.

  • defaultChannelPassword

    Password for the default channel. Pass an empty string if no password is required or no default channel is specified.

  • serverPassword

    Password for the server. Pass an empty string if the server does not require a password.

All strings need to be encoded in UTF-8 format.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. When trying to connect with an invalid identity, the Client Lib will set the error ERROR_client_could_not_validate_identity.


-

There is an alternative convinience function to start the connection which takes a channelID as parameter for the default channel instead of a channel name string array. -

unsigned int ts3client_startConnectionWithChannelID(serverConnectionHandlerID,  
 identity,  
 ip,  
 port,  
 nickname,  
 defaultChannelId,  
 defaultChannelPassword,  
 serverPassword); 
uint64 serverConnectionHandlerID;
const char* identity;
const char* ip;
unsigned int port;
const char* nickname;
uint64 defaultChannelId;
const char* defaultChannelPassword;
const char* serverPassword;
 

-

  • serverConnectionHandlerID

    Unique identifier for this server connection. Created with ts3client_spawnNewServerConnectionHandler

  • identity

    The clients identity. This string has to be created by calling ts3client_createIdentity. Please note an application should create the identity only once, store the string locally and reuse it for future connections.

  • ip

    Hostname or IP of the TeamSpeak 3 server.

    If you pass a hostname instead of an IP, the Client Lib will try to resolve it to an IP, but the function may block for an unusually long period of time while resolving is taking place. If you are relying on the function to return quickly, we recommend to resolve the hostname yourself (e.g. asynchronously) and then call ts3client_startConnection with the IP instead of the hostname.

  • port

    UDP port of the TeamSpeak 3 server, by default 9987. TeamSpeak 3 uses UDP. Support for TCP might be added in the future.

  • nickname

    On login, the client attempts to take this nickname on the connected server. Note this is not necessarily the actually assigned nickname, as the server can modifiy the nickname ("gandalf_1" instead the requested "gandalf") or refuse blocked names.

  • defaultChannelID

    Specifies ID of the channel on the TeamSpeak server we want to connect to. This is an alternative way to define the channel by ID instead of channel path as in ts3client_startConnection. If the specified channel does no longer exist or if the channel password is incorrect, the user will be connected to the default channel of the TeamSpeak server.

  • defaultChannelPassword

    Password for the default channel. Pass an empty string if no password is required or no default channel is specified.

  • serverPassword

    Password for the server. Pass an empty string if the server does not require a password.


-  

Example code to request a connection to a TeamSpeak 3 server:

unsigned int error;
-uint64 scHandlerID;
-char* identity;
-
-error = ts3client_spawnNewServerConnectionHandler(&scHandlerID);
-if(error != ERROR_ok) {
-    printf("Error spawning server conection handler: %d\n", error);
-    return;
-}
-
-error = ts3client_createIdentity(&identity);  /* Application should store and reuse the identity */
-if(error != ERROR_ok) {
-    printf("Error creating identity: %d\n", error);
-    return;
-}
-
-error = ts3client_startConnection(scHandlerID,
-                                  identity
-                                  "my-teamspeak-server.com",
-				  9987,
-				  "Gandalf",
-				  NULL,      // Join servers default channel
-				  "",        // Empty default channel password
-				  "secret"); // Server password
-if(error != ERROR_ok) {
-    (...)
-}			  
-ts3client_freeMemory(identity);  /* Don't need this anymore */


-

After calling ts3client_startConnection, the client will be informed of the connection status changes by the callback

void onConnectStatusChangeEvent(serverConnectionHandlerID,  
 newStatus,  
 errorNumber); 
uint64 serverConnectionHandlerID;
int newStatus;
int errorNumber;
 
  • newStatus

    The new connect state as defined by the enum ConnectStatus:

    enum ConnectStatus {
    -    STATUS_DISCONNECTED = 0,       //There is no activity to the server, this is the default value
    -    STATUS_CONNECTING,             //We are trying to connect, we haven't got a clientID yet, we
    -                                   //haven't been accepted by the server
    -    STATUS_CONNECTED,              //The server has accepted us, we can talk and hear and we got a
    -                                   //clientID, but we don't have the channels and clients yet, we
    -                                   //can get server infos (welcome msg etc.)
    -    STATUS_CONNECTION_ESTABLISHING,//we are CONNECTED and we are visible
    -    STATUS_CONNECTION_ESTABLISHED, //we are CONNECTED and we have the client and channels available
    -};
  • errorNumber

    Should be ERROR_ok (zero) when connecting

- While connecting, the states will switch through the values STATUS_CONNECTING, STATUS_CONNECTED and STATUS_CONNECTION_ESTABLISHED. Once the state STATUS_CONNECTED has been reached, there the server welcome message is available, which can be queried by the client:

  • Welcome message

    Query the server variable VIRTUALSERVER_WELCOMEMESSAGE for the message text using the function ts3client_getServerVariableAsString:

    char* welcomeMsg;
    -if(ts3client_getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_WELCOMEMESSAGE, &welcomeMsg)
    -   != ERROR_ok) {
    -    printf("Error getting server welcome message: %d\n", error);
    -    return;
    -}
    -print("Welcome message: %s\n", welcomeMsg);  /* Display message */
    -ts3client_freeMemory(welcomeMsg);  /* Release memory */


-

To check if a connection to a given server connection handler is established, call: -

unsigned int ts3client_getConnectionStatus(serverConnectionHandlerID,  
 result); 
uint64 serverConnectionHandlerID;
int* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler of which the connection state is checked.

  • result

    Address of a variable that receives the result: 1 - Connected, 0 - Not connected.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

After the state STATUS_CONNECTED has been reached, the client is assigned an ID which identifies the client on this server. This ID can be queried with -

unsigned int ts3client_getClientID(serverConnectionHandlerID,  
 result); 
uint64 serverConnectionHandlerID;
anyID* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which we are querying the own client ID.

  • result

    Address of a variable that receives the client ID. Client IDs start with the value 1.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

After connection has been established, all current channels on the server are announced to the client. This happens with delays to avoid a flood of information after connecting. The client is informed about the existance of each channel with the following event:

void onNewChannelEvent(serverConnectionHandlerID,  
 channelID,  
 channelParentID); 
uint64 serverConnectionHandlerID;
uint64 channelID;
uint64 channelParentID;
 
  • serverConnectionHandlerID

    The server connection handler ID.

  • channelID

    The ID of the announced channel.

  • channelParentID

    ID of the parent channel.

Channel IDs start with the value 1.

The order in which channels are announced by onNewChannelEvent is defined by the channel order as explained in the chapter Channel sorting.

All clients currently logged to the server are announced after connecting with the callback onClientMoveEvent.

diff --git a/pluginsdk/docs/client_html/ar01s10.html b/pluginsdk/docs/client_html/ar01s10.html deleted file mode 100644 index 4872f2d..0000000 --- a/pluginsdk/docs/client_html/ar01s10.html +++ /dev/null @@ -1,5 +0,0 @@ -Disconnecting from a server

Disconnecting from a server

To disconnect from a TeamSpeak 3 server call -

unsigned int ts3client_stopConnection(serverConnectionHandlerID,  
 quitMessage); 
uint64 serverConnectionHandlerID;
const char* quitMessage;
 

-

  • serverConnectionHandlerID

    The unique ID for this server connection handler.

  • quitMessage

    A message like for example "leaving". The string needs to be encoded in UTF-8 format.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

Like with connecting, on successful disconnecting the client will receive an event:


-

void onConnectStatusChangeEvent(serverConnectionHandlerID,  
 newStatus,  
 errorNumber); 
uint64 serverConnectionHandlerID;
int newStatus;
int errorNumber;
 
  • newStatus

    Set to STATUS_DISCONNECTED as defined by the enum ConnectStatus.

  • errorNumber

    errorNumber is expected to be ERROR_ok as response to calling ts3client_stopConnection.

    Values other than ERROR_ok occur when the connection has been lost for reasons not initiated by the user, e.g. network error, forcefully disconnected etc.


-

Should the server be shutdown, the follow event will be called:

void onServerStopEvent(serverConnectionHandlerID,  
 shutdownMessage); 
uint64 serverConnectionHandlerID;
const char* shutdownMessage;
 
  • serverConnectionHandlerID

    Server connection handler ID of the stopped server.

  • shutdownMessage

    Message announcing the reason for the shutdown sent by the server. Has to be encoded in UTF-8 format.

diff --git a/pluginsdk/docs/client_html/ar01s11.html b/pluginsdk/docs/client_html/ar01s11.html deleted file mode 100644 index be5e4a8..0000000 --- a/pluginsdk/docs/client_html/ar01s11.html +++ /dev/null @@ -1,27 +0,0 @@ -Error handling

Error handling

Each Client Lib function returns either ERROR_ok on success or an error value as defined in public_errors.h if the function fails.

The returned error codes are organized in groups, where the first byte defines the error group and the second the count within the group: The naming convention is ERROR_<group>_<error>, for example ERROR_client_invalid_id.

Example:

unsigned int error;
-char* welcomeMsg;
-
-error = ts3client_getServerVariableAsString(serverConnectionHandlerID,
-                                            VIRTUALSERVER_WELCOMEMESSAGE,
-                                            &welcomeMsg);
-if(error == ERROR_ok) {
-    /* Use welcomeMsg... */
-    ts3client_freeMemory(welcomeMsg);  /* Release memory *only* if function did not return an error */
-} else {
-    /* Handle error */
-    /* Do not access or release welcomeMessage, the variable is undefined */
-}
[Important]Important

Client Lib functions returning C-strings or arrays dynamically allocate memory which has to be freed by the caller using ts3client_freeMemory. It is important to only access and release the memory if the function returned ERROR_ok. Should the function return an error, the result variable is uninitialized, so freeing or accessing it could crash the application.

See the section Calling Client Lib functions for additional notes and examples.


-

A printable error string for a specific error code can be queried with -

unsigned int ts3client_getErrorMessage(errorCode,  
 error); 
unsigned int errorCode;
char** error;
 

-

  • errorCode

    The error code returned from all Client Lib functions.

  • error

    Address of a variable that receives the error message string, encoded in UTF-8 format. Unless the return value of the function is not ERROR_ok, the string should be released with ts3client_freeMemory.

Example:

unsigned int error;
-anyID myID;
-
-error = ts3client_getClientID(scHandlerID, &myID);  /* Calling some Client Lib function */
-if(error != ERROR_ok) {
-    char* errorMsg;
-    if(ts3client_getErrorMessage(error, &errorMsg) == ERROR_ok) {  /* Query printable error */
-        printf("Error querying client ID: %s\n", errorMsg);
-        ts3client_freeMemory(errorMsg);  /* Release memory */
-    }
-}


-

In addition to actively querying errors like above, error codes can be sent by the server to the client. In that case the following event is called:

void onServerErrorEvent(serverConnectionHandlerID,  
 errorMessage,  
 error,  
 returnCode,  
 extraMessage); 
uint64 serverConnectionHandlerID;
const char* errorMessage;
unsigned int error;
const char* returnCode;
const char* extraMessage;
 
  • serverConnectionHandlerID

    The connection handler ID of the server who sent the error event.

  • errorMessage

    String containing a verbose error message, encoded in UTF-8 format.

  • error

    Error code as defined in public_errors.h.

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.

  • extraMessage

    Can contain additional information about the occured error. If no additional information is available, this parameter is an empty string.

diff --git a/pluginsdk/docs/client_html/ar01s12.html b/pluginsdk/docs/client_html/ar01s12.html deleted file mode 100644 index b9229c9..0000000 --- a/pluginsdk/docs/client_html/ar01s12.html +++ /dev/null @@ -1,14 +0,0 @@ -Logging

Logging

The TeamSpeak 3 Client Lib offers basic logging functions: - -

unsigned int ts3client_logMessage(logMessage,  
 severity,  
 channel,  
 logID); 
const char* logMessage;
LogLevel severity;
const char* channel;
uint64 logID;
 

-

  • logMessage

    Text written to log.

  • severity

    The level of the message, warning or error. Defined by the enum LogLevel in clientlib_publicdefinitions.h:

    enum LogLevel {
    -    LogLevel_CRITICAL = 0, //these messages stop the program
    -    LogLevel_ERROR,        //everything that is really bad, but not so bad we need to shut down
    -    LogLevel_WARNING,      //everything that *might* be bad
    -    LogLevel_DEBUG,        //output that might help find a problem
    -    LogLevel_INFO,         //informational output, like "starting database version x.y.z"
    -    LogLevel_DEVEL         //developer only output (will not be displayed in release mode)
    -};
  • channel

    Custom text to categorize the message channel (i.e. "Client", "Sound").

    Pass an empty string if unused.

  • logID

    Server connection handler ID to identify the current server connection when using multiple connections.

    Pass 0 if unused.

All strings need to be encoded in UTF-8 format.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

Log messages can be printed to stdout, logged to a file logs/ts3client_[date]__[time].log and sent to user-defined callbacks. The log output behaviour is defined when initialzing the client library with ts3client_initClientLib.

Unless user-defined logging is used, program execution will halt on a log message with severity LogLevel_CRITICAL.

User-defined logging

If user-defined logging was enabled when initialzing the Client Lib by passing LogType_USERLOGGING to the usedLogTypes parameter of ts3client_initClientLib, log messages will be sent to the following callback, which allows user customizable logging and handling or critical errors:

void onUserLoggingMessageEvent(logMessage,  
 logLevel,  
 logChannel,  
 logID,  
 logTime,  
 completeLogString); 
const char* logMessage;
int logLevel;
const char* logChannel;
uint64 logID;
const char* logTime;
const char* completeLogString;
 

Most callback parameters reflect the arguments passed to the logMessage function.

  • logMessage

    Actual log message text.

  • logLevel

    Severity of log message, defined by the enum LogLevel. Note that only log messages of a level higher than the one configured with ts3client_setLogVerbosity will appear.

  • logChannel

    Optional custom text to categorize the message channel.

  • logID

    Server connection handler ID identifying the current server connection when using multiple connections.

  • logTime

    String with date and time when the log message occured.

  • completeLogString

    Provides a verbose log message including all previous parameters for convinience.


-

The severity of log messages that are passed to above callback can be configured with: -

unsigned int ts3client_setLogVerbosity(logVerbosity); 
enum LogLevel logVerbosity;
 

-

  • logVerbosity

    Only messages with a log level equal or higher than logVerbosity will be sent to the callback. The default value is LogLevel_DEVEL.

    For example, after calling

    ts3client_setLogVerbosity(LogLevel_ERROR);

    only log messages of level LogLevel_ERROR and LogLevel_CRITICAL will be passed to onUserLoggingMessageEvent.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

diff --git a/pluginsdk/docs/client_html/ar01s13.html b/pluginsdk/docs/client_html/ar01s13.html deleted file mode 100644 index 153a644..0000000 --- a/pluginsdk/docs/client_html/ar01s13.html +++ /dev/null @@ -1,9 +0,0 @@ -Using playback and capture modes and devices

Using playback and capture modes and devices

The Client Lib takes care of initializing, using and releasing sound playback and capture devices. Accessing devices is handled by the sound backend shared libraries, found in the soundbackends directory in the SDK. There are different backends available on the supported operating systems: DirectSound and Windows Audio Session API on Windows, Alsa and PulseAudio on Linux, CoreAudio on Mac OS X.

All strings passed to and from the Client Lib have to be encoded in UTF-8 format.

Initializing modes and devices

To initialize a playback and capture device for a TeamSpeak 3 server connection handler, call -

unsigned int ts3client_openPlaybackDevice(serverConnectionHandlerID,  
 modeID,  
 playbackDevice); 
uint64 serverConnectionHandlerID;
const char* modeID;
const char* playbackDevice;
 

-

  • serverConnectionHandlerID

    Connection handler of the server on which you want to initialize the playback device.

  • modeID

    The playback mode to use. Valid modes are returned by ts3client_getDefaultPlayBackMode and ts3client_getPlaybackModeList.

    Passing an empty string will use the default playback mode.

  • playbackDevice

    Valid parameters are: -

    - The string needs to be encoded in UTF-8 format. -

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. A likely error is ERROR_sound_could_not_open_playback_device if the sound backend fails to find a usable playback device.


-

unsigned int ts3client_openCaptureDevice(serverConnectionHandlerID,  
 modeID,  
 captureDevice); 
uint64 serverConnectionHandlerID;
const char* modeID;
const char* captureDevice;
 
  • serverConnectionHandlerID

    Connection handler of the server on which you want to initialize the capture device.

  • modeID

    The capture mode to use. Valid modes are returned by ts3client_getDefaultCaptureMode and ts3client_getCaptureModeList.

    Passing an empty string will use the default capture mode.

  • captureDevice

    Valid parameters are: -

    -

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. Likely errors are ERROR_sound_could_not_open_capture_device if the device fails to open or ERROR_sound_handler_has_device if the device is already opened. To avoid this problem, it is recommended to close the capture device before opening it again.

diff --git a/pluginsdk/docs/client_html/ar01s13s02.html b/pluginsdk/docs/client_html/ar01s13s02.html deleted file mode 100644 index 7d4f4fb..0000000 --- a/pluginsdk/docs/client_html/ar01s13s02.html +++ /dev/null @@ -1,69 +0,0 @@ -Querying available modes and devices

Querying available modes and devices

Various playback and capture modes are available: DirectSound on all Windows platforms, Windows Audio Session API for Windows Vista and Windows 7; Alsa and PulseAudio on Linux; CoreAudio on Mac OS X.

Available device names may differ depending on the current mode.

The default playback and capture modes can be queried with: -

unsigned int ts3client_getDefaultPlayBackMode(result); 
char** result;
 

- -

unsigned int ts3client_getDefaultCaptureMode(result); 
char** result;
 

-

  • result

    Address of a variable that receives the default playback or capture mode. The value can be used as parameter for the functions querying and opening devices. Unless the function returns an error, the string must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

All available playback and capture modes can be queried with: -

unsigned int ts3client_getPlaybackModeList(result); 
char*** result;
 

- -

unsigned int ts3client_getCaptureModeList(result); 
char*** result;
 

-

  • result

    Address of a variable that receives a NULL-terminated array of C-strings listing available playback or capture modes.

    Unless the function returns an error, the caller must release each element of the array (the C-string) and finally the complete array with ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. In case of an error, the result array is uninitialized and must not be accessed or released.

Example to query all available playback modes:

char** array;
-
-if(ts3client_getPlaybackModeList(&array) == ERROR_ok) {
-    for(int i=0; array[i] != NULL; ++i) {
-        printf("Mode: %s\n", array[i]);
-        ts3client_freeMemory(array[i]);  // Free C-string
-    }
-    ts3client_freeMemory(array);  // Free the array
-}


-

Playback and capture devices available for the given mode can be listed, as well as the current operating systems default. The returned device values can be used to initialize the devices.

To query the default playback and capture device, call -

unsigned int ts3client_getDefaultPlaybackDevice(modeID,  
 result); 
const char* modeID;
char*** result;
 

- -

unsigned int ts3client_getDefaultCaptureDevice(modeID,  
 result); 
const char* modeID;
char*** result;
 

-

  • mode

    Defines the playback/capture mode to use. For different modes there might be different default devices. Valid modes are returned by ts3client_getDefaultPlayBackMode / ts3client_getDefaultCaptureMode and ts3client_getPlaybackModeList / ts3client_getCaptureModeList.

  • result

    Address of a variable that receives an array of two C-strings. The first element contains the device name, the second the device ID.

    Unless the function returns an error, the caller must free the two array elements and the complete array with ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. In case of an error, the result array is uninitialized and must not be released.

Example to query the default playback device:

char* defaultMode;
-
-/* Get default playback mode */
-if(ts3client_getDefaultPlayBackMode(&defaultMode) == ERROR_ok) {
-    char** defaultPlaybackDevice;
-
-    /* Get default playback device */
-    if(ts3client_getDefaultPlaybackDevice(defaultMode, &defaultPlaybackDevice) == ERROR_ok) {
-        printf("Default playback device name: %s\n", defaultPlaybackDevice[0]);  /* First element: Device name */
-        printf("Default playback device ID: %s\n",   defaultPlaybackDevice[1]);  /* Second element: Device ID */
-
-        /* Release the two array elements and the array */
-        ts3client_freeMemory(defaultPlaybackDevice[0]);
-        ts3client_freeMemory(defaultPlaybackDevice[1]);
-        ts3client_freeMemory(defaultPlaybackDevice);
-    } else {
-        printf("Failed to get default playback device\n");
-    }
-} else {
-    printf("Failed to get default playback mode\n");
-}


-

To get a list of all available playback and capture devices for the specified mode, call -

unsigned int ts3client_getPlaybackDeviceList(modeID,  
 result); 
const char* modeID;
char**** result;
 

- -

unsigned int ts3client_getCaptureDeviceList(modeID,  
 result); 
const char* modeID;
char**** result;
 

-

  • modeID

    Defines the playback/capture mode to use. For different modes there might be different device lists. Valid modes are returned by ts3client_getDefaultPlayBackMode / ts3client_getDefaultCaptureMode and ts3client_getPlaybackModeList / ts3client_getCaptureModeList.

  • result

    Address of a variable that receives a NULL-terminated array { { char* deviceName, char* deviceID }, { char* deviceName, char* deviceID }, ... , NULL }.

    Unless the function returns an error, the elements of the array and the array itself need to be freed using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. In case of an error, the result array is uninitialized and must not be released.

Example to query all available playback devices:

char* defaultMode;
-
-if(ts3client_getDefaultPlayBackMode(&defaultMode) == ERROR_ok) {
-    char*** array;
-
-    if(ts3client_getPlaybackDeviceList(defaultMode, &array) == ERROR_ok) {
-        for(int i=0; array[i] != NULL; ++i) {
-            printf("Playback device name: %s\n", array[i][0]);  /* First element: Device name */
-            printf("Playback device ID: %s\n",   array[i][1]);  /* Second element: Device ID */
-
-            /* Free element */
-            ts3client_freeMemory(array[i][0]);
-            ts3client_freeMemory(array[i][1]);
-            ts3client_freeMemory(array[i]);
-        }
-        ts3client_freeMemory(array);  /* Free complete array */
-    } else {
-        printf("Error getting playback device list\n");
-    }
-} else {
-    printf("Error getting default playback mode\n");
-}
diff --git a/pluginsdk/docs/client_html/ar01s13s03.html b/pluginsdk/docs/client_html/ar01s13s03.html deleted file mode 100644 index f1333ac..0000000 --- a/pluginsdk/docs/client_html/ar01s13s03.html +++ /dev/null @@ -1,10 +0,0 @@ -Checking current modes and devices

Checking current modes and devices

The currently used playback and capture modes for a given server connection handler can be checked with: -

unsigned int ts3client_getCurrentPlayBackMode(serverConnectionHandlerID,  
 result); 
uint64 serverConnectionHandlerID;
char** result;
 

- -

unsigned int ts3client_getCurrentCaptureMode(serverConnectionHandlerID,  
 result); 
uint64 serverConnectionHandlerID;
char** result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the current playback or capture modes are queried.

  • result

    Address of a variable that receives the current playback or capture mode. Unless the function returns an error, the string must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

Check the currently used playback and capture devices for a given server connection handler with: -

unsigned int ts3client_getCurrentPlaybackDeviceName(serverConnectionHandlerID,  
 result,  
 isDefault); 
uint64 serverConnectionHandlerID;
char** result;
int* isDefault;
 

- -

unsigned int ts3client_getCurrentCaptureDeviceName(serverConnectionHandlerID,  
 result,  
 isDefault); 
uint64 serverConnectionHandlerID;
char** result;
int* isDefault;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the current playback or capture devices are queried.

  • result

    Address of a variable that receives the current playback or capture device. Unless the function returns an error, the string must be released using ts3client_freeMemory.

  • result

    Address of a variable that receives a flag if this device is the default playback/capture device. If this is not needed, pass NULL instead.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the result string is uninitialized and must not be released.

diff --git a/pluginsdk/docs/client_html/ar01s13s04.html b/pluginsdk/docs/client_html/ar01s13s04.html deleted file mode 100644 index 9f895c9..0000000 --- a/pluginsdk/docs/client_html/ar01s13s04.html +++ /dev/null @@ -1,23 +0,0 @@ -Closing devices

Closing devices

To close the capture and playback devices for a given server connection handler: -

unsigned int ts3client_closeCaptureDevice(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

- -

unsigned int ts3client_closePlaybackDevice(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the playback or capture device should be closed.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

ts3client_closePlaybackDevice will not block until all current sounds have finished playing but will shutdown the device immediately, possibly interrupting the still playing sounds. To shutdown the playback device more gracefully, use the following function: -

unsigned int ts3client_initiateGracefulPlaybackShutdown(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the playback or capture device should be shut down.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

While ts3client_initiateGracefulPlaybackShutdown will not block until all sounds have finished playing, too, it will notify the client when the playback device can be safely closed by sending the callback: -

void onPlaybackShutdownCompleteEvent(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the playback device has been shut down.

Example code to gracefully shutdown the playback devicef:

/* Instead of calling ts3client_closePlaybackDevice() directly */
-if(ts3client_initiateGracefulPlaybackShutdown(currentScHandlerID) != ERROR_ok) {
-    printf("Failed to initiate graceful playback shutdown\n");
-    return;
-}
-
-/* Event notifying the playback device has been shutdown */
-void my_onPlaybackShutdownCompleteEvent(uint64 scHandlerID) {
-    /* Now we can safely close the device */
-    if(ts3client_closePlaybackDevice(scHandlerID) != ERROR_ok) {
-        printf("Error closing playback device\n");
-    }
-}
[Note]Note

Devices are closed automatically when calling ts3client_destroyServerConnectionHandler.

[Note]Note

To change a device, close it first and then reopen it.

diff --git a/pluginsdk/docs/client_html/ar01s13s05.html b/pluginsdk/docs/client_html/ar01s13s05.html deleted file mode 100644 index b3755a4..0000000 --- a/pluginsdk/docs/client_html/ar01s13s05.html +++ /dev/null @@ -1,44 +0,0 @@ -Using custom devices

Using custom devices

Instead of opening existing sound devices that TeamSpeak has detected, you can also use our custom capture and playback mechanism to allow you to override the way in which TeamSpeak does capture and playback. When you have opened a custom capture and playback device you must regularly supply new "captured" sound data via the ts3client_processCustomCaptureData function and retrieve data that should be "played back" via ts3client_acquireCustomPlaybackData. Where exactly this captured sound data comes from and where the playback data goes to is up to you, which allows a lot of cool things to be done with this mechanism.

Implementing own custom devices is for special use cases and entirely optional.

Registering a custom device announces the device ID and name to the Client Lib. Once a custom device has been registered under a device ID, the device can be opened like any standard device with ts3client_openCaptureDevice and ts3client_openPlaybackDevice.

void ts3client_registerCustomDevice(deviceID,  
 deviceDisplayName,  
 capFrequency,  
 capChannels,  
 playFrequency,  
 playChannels); 
const char* deviceID;
const char* deviceDisplayName;
int capFrequency;
int capChannels;
int playFrequency;
int playChannels;
 
  • deviceID

    ID string of the custom device, under which the device can be later accessed.

  • deviceDisplayName

    Displayed name of the custom device. Freely choose a name which identifies your device.

  • capFrequency

    Frequency of the capture device.

  • capChannels

    Number of channels of the capture device. This value depends on if the used codec is a mono or stereo codec.

  • playFrequency

    Frequency of the playback device.

  • playChannels

    Number of channels of the playback device.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

Unregistering a custom device will automatically close the device:

void ts3client_unregisterCustomDevice(deviceID); 
const char* deviceID;
 
  • deviceID

    ID string of the custom device to unregister. This is the ID under which the device was registered with ts3client_registerCustomDevice.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

To send the captured data from your device to the Client Lib:

void ts3client_processCustomCaptureData(deviceID,  
 buffer,  
 samples); 
const char* deviceID;
const short* buffer;
int samples;
 
  • deviceID

    ID string of the custom device. This is the ID under which the device was registered with ts3client_registerCustomDevice.

  • buffer

    Capture data buffer containing the data captured by the custom device.

  • samples

    Size of the capture data buffer.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

Retrieve playback data from the Client Lib:

void ts3client_acquireCustomPlaybackData(deviceID,  
 buffer,  
 samples); 
const char* deviceID;
const short* buffer;
int samples;
 
  • deviceID

    ID string of the custom device. This is the ID under which the device was registered with ts3client_registerCustomDevice.

  • buffer

    Buffer containing the playback data retrieved from the Client Lib.

  • samples

    Size of the playback data buffer.

Returns ERROR_ok if playback data is available or ERROR_sound_no_data if the Client Lib currently has no playback data.

The return value ERROR_sound_no_data can be used for performance optimisation, it means there is currently only silence (nobody is talking, no wave files being played etc.) and instead of returning a buffer full of zeroes it just notifies the user there is currently no data, which allows you to not playback any sound data for that moment, if your API supports that (potentially saving some CPU), or to just fill the sound buffer with zeroes and playback this if your sound API demands you to fill it with something for every given time.


-

Overview on registering and opening a custom device:

/* Register a new custom sound device with specified frequency and number of channels */
-if(ts3client_registerCustomDevice("customWaveDeviceId", "Nice displayable wave device name", captureFrequency, captureChannels, playbackFrequncy, playbackChannels) != ERROR_ok) {
-    printf("Failed to register custom device\n");
-}
-
-/* Open capture device we created earlier */
-if(ts3client_openCaptureDevice(scHandlerID, "custom", "customWaveDeviceId") != ERROR_ok) {
-    printf("Error opening capture device\n");
-}
-
-/* Open playback device we created earlier */
-if(ts3client_openPlaybackDevice(scHandlerID, "custom", "customWaveDeviceId") != ERROR_ok) {
-    printf("Error opening playback device\n");
-}
-
-/* Main loop */
-while(!abort) {
-    /* Fill captureBuffer from your custom device */
-
-    /* Stream your capture data to the client lib */
-	if(ts3client_processCustomCaptureData("customWaveDeviceId", captureBuffer, captureBufferSize) != ERROR_ok) {
-        printf("Failed to process capture data\n");
-    }
-
-    /* Get playback data from the client lib */
-    error = ts3client_acquireCustomPlaybackData("customWaveDeviceId", playbackBuffer, playbackBufferSize);
-    if(error == ERROR_ok) {
-        /* Playback data available, send playbackBuffer to your custom device */
-    } else if(error == ERROR_sound_no_data) {
-        /* Not an error. The client lib has no playback data available. Depending on your custom sound API, either
-           pause playback for performance optimisation or send a buffer of zeros. */
-    } else {
-        printf("Failed to get playback data\n");  /* Error occured */
-    }
-}
-
-/* Unregister the custom device. This automatically close the device. */
-if(ts3client_unregisterCustomDevice("customaveDeviceId") != ERROR_ok) {
-    printf("Failed to unregister custom device\n");
-}
[Note]Note

Further sample code on how to use a custom device can be found in the “client_customdevice” example included in the SDK.

diff --git a/pluginsdk/docs/client_html/ar01s13s06.html b/pluginsdk/docs/client_html/ar01s13s06.html deleted file mode 100644 index 2f79def..0000000 --- a/pluginsdk/docs/client_html/ar01s13s06.html +++ /dev/null @@ -1 +0,0 @@ -Activating the capture device

Activating the capture device

[Note]Note

Using this function is only required when connecting to multiple servers.

When connecting to multiple servers with the same client, the capture device can only be active for one server at the same time. As soon as the client connects to a new server, the Client Lib will deactivate the capture device of the previously active server. When a user wants to talk to that previous server again, the client needs to reactivate the capture device.

unsigned int ts3client_activateCaptureDevice(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the capture device should be activated.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

If the capture device is already active, this function has no effect.

Opening a new capture device will automatically activate it, so calling this function is only necessary with multiple server connections and when reactivating a previously deactivated device.

If the capture device for a given server connection handler has been deactivated by the Client Lib, the flag CLIENT_INPUT_HARDWARE will be set. This can be queried with the function ts3client_getClientSelfVariableAsInt.

diff --git a/pluginsdk/docs/client_html/ar01s14.html b/pluginsdk/docs/client_html/ar01s14.html deleted file mode 100644 index 54c0f07..0000000 --- a/pluginsdk/docs/client_html/ar01s14.html +++ /dev/null @@ -1,3 +0,0 @@ -Sound codecs

Sound codecs

TeamSpeak 3 supports the following sound sampling rates:

  • Speex Narrowband (8 kHz)

  • Speex Wideband (16 kHz)

  • Speex Ultra-Wideband (32 kHz)

  • Celt (Mono, 48kHz)

  • Opus Voice (Mono, 48khz)

  • Opus Music (Stereo, 48khz)

[Note]Note

Opus Voice is recommended for voice transmission. Speex and Celt codecs may be removed in future versions of this SDK.


-

Bandwidth usage generally depends on the used codec and the encoders quality setting.

Estimated bitrates (bps) for codecs per quality:

QualityNarrowbandWidebandUltra-WidebandCeltOpus VoiceOpus Music
02,1503,9504,15032,0004,0967,200
13,9505,7507,55032,0008,19214,400
25,9507,7509,55040,00012,28821,600
38,0009,80011,60040,00016,38428,800
48,00012,80014,60040,00020,48036,000
511,00016,80018,60048,00024,57643,200
611,00020,60022,40048,00028,67250,400
715,00023,80025,60048,00032,76857,600
815,00027,80029,60048,00036,86464,800
918,20034,40036,20064,00040,96072,000
1024,60042,40044,20096,00045,05679,200

Change the quality to find a good middle between voice quality and bandwidth usage. Overall the Opus codec delivers the best quality per used bandwidth.

Users need to use the same codec when talking to each others. The smallest unit of participants using the same codec is a channel. Different channels on the same TeamSpeak 3 server can use different codecs. The channel codec should be customizable by the users to allow for flexibility concerning bandwidth vs. quality concerns.

The codec can be set or changed for a given channel using the function ts3client_setChannelVariableAsInt by passing CHANNEL_CODEC for the properties flag:

ts3client_setChannelVariableAsInt(scHandlerID, channelID, CHANNEL_CODEC, codec);

Available values for CHANNEL_CODEC are: -

  • 0 - Speex Narrowband)

  • 1 - Speex Wideband

  • 2 - Speex Ultra-Wideband

  • 3 - Celt

  • 4 - Opus Voice

  • 5 - Opus Music

For details on using the function ts3client_setChannelVariableAsInt see the appropriate section on changing channel data.

diff --git a/pluginsdk/docs/client_html/ar01s15.html b/pluginsdk/docs/client_html/ar01s15.html deleted file mode 100644 index d301d47..0000000 --- a/pluginsdk/docs/client_html/ar01s15.html +++ /dev/null @@ -1,13 +0,0 @@ -Encoder options

Encoder options

Speech quality and bandwidth usage depend on the used Speex encoder. As Speex is a lossy code, the quality value controls the balance between voice quality and network traffic. Valid quality values range from 0 to 10, default is 7. The encoding quality can be configured for each channel using the CHANNEL_CODEC_QUALITY property. The currently used channel codec, codec quality and estimated average used bitrate (without overhead) can be queried with ts3client_getEncodeConfigValue.

[Note]Note

Encoder options are tied to a capture device, so querying the values only makes sense after a device has been opened.

All strings passed from the Client Lib are encoded in UTF-8 format.

unsigned int ts3client_getEncodeConfigValue(serverConnectionHandlerID,  
 ident,  
 result); 
uint64 serverConnectionHandlerID;
const char* ident;
char** result;
 
  • serverConnectionHandlerID

    Server connection handler ID

  • ident

    String containing the queried encoder option. Available values are “name”, “quality” and “bitrate”.

  • result

    Address of a variable that receives the result string. Unless an error occured, the result string must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the result string is uninitialized and must not be released.

To adjust the channel codec quality to a value of 5, you would call: -

ts3client_setChannelVariableAsInt(scHandlerID, channelID, CHANNEL_CODEC_QUALITY, 5);

See the chapter about channel information for details about how to set channel variables.

To query information about the current channel quality, do: -

char *name, *quality, *bitrate;
-ts3client_getEncodeConfigValue(scHandlerID, "name", &name);
-ts3client_getEncodeConfigValue(scHandlerID, "quality", &quality);
-ts3client_getEncodeConfigValue(scHandlerID, "bitrate", &bitrate);
-
-printf("Name = %s, quality = %s, bitrate = %s\n", name, quality, bitrate);
-
-ts3client_freeMemory(name);
-ts3client_freeMemory(quality);
-ts3client_freeMemory(bitrate);

-

diff --git a/pluginsdk/docs/client_html/ar01s16.html b/pluginsdk/docs/client_html/ar01s16.html deleted file mode 100644 index 299b2a9..0000000 --- a/pluginsdk/docs/client_html/ar01s16.html +++ /dev/null @@ -1,9 +0,0 @@ -Preprocessor options

Preprocessor options

Sound input is preprocessed by the Client Lib before the data is encoded and sent to the TeamSpeak 3 server. The preprocessor is responsible for noise suppression, automatic gain control (AGC) and voice activity detection (VAD).

The preprocessor can be controlled by setting various preprocessor flags. These flags are unique to each server connection.

[Note]Note

Preprocessor flags are tied to a capture device, so changing the values only makes sense after a device has been opened.

Preprocessor flags can be queried using -

unsigned int ts3client_getPreProcessorConfigValue(serverConnectionHandlerID,  
 ident,  
 result); 
uint64 serverConnectionHandlerID;
const char* ident;
char** result;
 

-

  • serverConnectionHandlerID

    The server connection handler ID.

  • ident

    The proprocessor flag to be queried. The following keys are available:

    • name

      Type of the used preprocessor. Currently this returns a constant string “Speex preprocessor”.

    • denoise

      Check if noise suppression is enabled. Returns “true” or “false”.

    • vad

      Check if Voice Activity Detection is enabled. Returns “true” or “false”.

    • voiceactivation_level

      Checks the Voice Activity Detection level in decibel. Returns a string with a numeric value, convert this to an integer.

    • vad_extrabuffersize

      Checks Voice Activity Detection extrabuffer size. Returns a string with a numeric value.

    • agc

      Check if Automatic Gain Control is enabled. Returns “true” or “false”.

    • agc_level

      Checks AGC level. Returns a string with a numeric value.

    • agc_max_gain

      Checks AGC max gain. Returns a string with a numeric value.

    • echo_canceling

      Checks if echo canceling is enabled. Returns a string with a boolean value.

  • result

    Address of a variable that receives the result as a string encoded in UTF-8 format. If no error occured the returned string must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the result string is uninitialized and must not be released.


-

To configure the proprocessor use -

unsigned int ts3client_setPreProcessorConfigValue(serverConnectionHandlerID,  
 ident,  
 value); 
uint64 serverConnectionHandlerID;
const char* ident;
const char* value;
 

-

  • serverConnectionHandlerID

    The server connection handler ID.

  • ident

    The preprocessor flag to be configure. The following keys can be changed:

    • denoise

      Enable or disable noise suppression. Value can be “true” or “false”. Enabled by default.

    • vad

      Enable or disable Voice Activity Detection. Value can be “true” or “false”. Enabled by default.

    • voiceactivation_level

      Voice Activity Detection level in decibel. Numeric value converted to string. A high voice activation level means you have to speak louder into the microphone in order to start transmitting.

      Reasonable values range from -50 to 50. Default is 0.

      To adjust the VAD level in your client, you can call ts3client_getPreProcessorInfoValueFloat with the identifier “decibel_last_period” over a period of time to query the current voice input level.

    • vad_extrabuffersize

      Voice Activity Detection extrabuffer size. Numeric value converted to string. Should be “0” to “8”, defaults to “2”. Lower value means faster transmission, higher value means better VAD quality but higher latency.

    • agc

      Enable or disable Automatic Gain Control. Value can be “true” or “false”. Enabled by default.

    • agc_level

      AGC level. Numeric value converted to string. Default is “16000”.

    • agc_max_gain

      AGC max gain. Numeric value converted to string. Default is “30”.

    • echo_canceling

      Enable echo canceling. Boolean value converted to string. Default is “false”.

  • value

    String value to be set for the given preprocessor identifier. In case of on/off switches, use “true” or “false”.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

[Note]Note

It is not necessary to change all those values. The default values are reasonable. “voiceactivation_level” is often the only value that needs to be adjusted.


-

The following function retrieves preprocessor information as a floating-point variable instead of a string: -

unsigned int ts3client_getPreProcessorInfoValueFloat(serverConnectionHandlerID,  
 ident,  
 result); 
uint64 serverConnectionHandlerID;
const char* ident;
float* result;
 

-

  • serverConnectionHandlerID

    The server connection handler ID.

  • ident

    The proprocessor flag to be queried. Currently the only valid identifier for this function is “decibel_last_period”, which can be used to adjust the VAD level as described above.

  • result

    Address of a variable that receives the result value as a float.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

diff --git a/pluginsdk/docs/client_html/ar01s17.html b/pluginsdk/docs/client_html/ar01s17.html deleted file mode 100644 index d1b39a3..0000000 --- a/pluginsdk/docs/client_html/ar01s17.html +++ /dev/null @@ -1,32 +0,0 @@ -Playback options

Playback options

Sound output can be configured using playback options. Currently the output value can be adjusted.

Playback options can be queried: -

unsigned int ts3client_getPlaybackConfigValueAsFloat(serverConnectionHandlerID,  
 ident,  
 result); 
uint64 serverConnectionHandlerID;
const char* ident;
float* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the playback option is queried.

  • ident

    Identifier of the parameter to be configured. Possible values are: -

    • volume_modifier

      Modify the voice volume of other speakers. Value is in decibel, so 0 is no modification, negative values make the signal quieter and values greater than zero boost the signal louder than it is. Be careful with high positive values, as you can really cause bad audio quality due to clipping. The maximum possible Value is 30.

      Zero and all negative values cannot cause clipping and distortion, and are preferred for optimal audio quality. Values greater than zero and less than +6 dB might cause moderate clipping and distortion, but should still be within acceptable bounds. Values greater than +6 dB will cause clipping and distortion that will negatively affect your audio quality. It is advised to choose lower values. Generally we recommend to not allow values higher than 15 db.

    • volume_factor_wave

      Adjust the volume of wave files played by ts3client_playWaveFile and ts3client_playWaveFileHandle. The value is a float defining the volume reduction in decibel. Reasonable values range from “-40.0” (very silent) to “0.0” (loudest).

  • result

    Address of a variable that receives the playback configuration value as floating-point number.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

To change playback options, call: -

unsigned int ts3client_setPlaybackConfigValue(serverConnectionHandlerID,  
 ident,  
 value); 
uint64 serverConnectionHandlerID;
const char* ident;
const char* value;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the playback option is queried.

  • ident

    Identifier of the parameter to be configured. The values are the same as in ts3client_getPlaybackConfigValueAsFloat above.

  • value

    String with the value to set the option to, encoded in UTF-8 format.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

[Note]Note

Playback options are tied to a playback device, so changing the values only makes sense after a device has been opened.

Example code:

unsigned int error;
-float value;
-
-if((error = ts3client_setPlaybackConfigValue(scHandlerID, "volume_modifier", "5.5")) != ERROR_ok) {
-    printf("Error setting playback config value: %d\n", error);
-    return;
-}
-
-if((error = ts3client_getPlaybackConfigValueAsFloat(scHandlerID, "volume_modifier", &value)) != ERROR_ok) {
-    printf("Error getting playback config value: %d\n", error);
-    return;
-}
-
-printf("Volume modifier playback option: %f\n", value);


-

In addition to changing the global voice volume modifier of all speakers by changing the “volume_modifier” parameter, voice volume of individual clients can be adjusted with: -

unsigned int ts3client_setClientVolumeModifier(serverConnectionHandlerID,  
 clientID,  
 value); 
uint64 serverConnectionHandlerID;
anyID clientID;
float value;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the client volume modifier should be adjusted.

  • clientID

    ID of the client whose volume modifier should be adjusted.

  • value

    The new client volume modifier value as float.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

When calculating the volume for individual clients, both the global and client volume modifiers will be taken into account.

Client volume modifiers are valid as long as the specified client is visible. Once the client leaves visibility by joining an unsubscribed channel or disconnecting from the server, the client volume modifier will be lost. When the client enters visibility again, the modifier has to be set again by calling this function.

Example:

-unsigned int error;
-anyID clientID = 123;
-float value = 10.0f;
-
-if((error = ts3client_setClientVolumeModifier(scHandlerID, clientID, value)) != ERROR_ok) {
-    printf("Error setting client volume modifier: %d\n", error);
-	return;
-}
-
diff --git a/pluginsdk/docs/client_html/ar01s18.html b/pluginsdk/docs/client_html/ar01s18.html deleted file mode 100644 index d08c01d..0000000 --- a/pluginsdk/docs/client_html/ar01s18.html +++ /dev/null @@ -1,19 +0,0 @@ -Accessing the voice buffer

Accessing the voice buffer

The TeamSpeak Client Lib allows users to access the raw playback and capture voice data and even modify it, for example to add effects to the voice. These callbacks are also used by the TeamSpeak client for the voice recording feature.

Using these low-level callbacks is not required and should be reserved for specific needs. Most SDK applications won't need to implement these callbacks.


-

The following event is called when a voice packet from a client (not own client) is decoded and about to be played over your sound device, but before it is 3D positioned and mixed with other sounds. You can use this function to alter the voice data (for example when you want to do effects on it) or to simply get voice data. The TeamSpeak client uses this function to record sessions.

void onEditPlaybackVoiceDataEvent(serverConnectionHandlerID,  
 clientID,  
 samples,  
 sampleCount,  
 channels); 
uint64 serverConnectionHandlerID;
anyID clientID;
short* samples;
int sampleCount;
int channels;
 
  • serverConnectionHandlerID

    ID of the server connection handler from which the voice data was sent.

  • clientID

    ID of the client whose voice data is received.

  • samples

    Pointer to the voice data (signed 16 bit @ 48KHz).

  • sampleCount

    Number of samples the "samples" variable points to.

  • channels

    Number of channels in the sound data.


-

The following event is called when a voice packet from a client (not own client) is decoded and 3D positioned and about to be played over your sound device, but before it is mixed with other sounds. You can use this function to alter/get the voice data after 3D positioning.

void onEditPostProcessVoiceDataEvent(serverConnectionHandlerID,  
 clientID,  
 samples,  
 sampleCount,  
 channels,  
 channelSpeakerArray,  
 channelFillMask); 
uint64 serverConnectionHandlerID;
anyID clientID;
short* samples;
int sampleCount;
int channels;
const unsigned int* channelSpeakerArray;
unsigned int* channelFillMask;
 
  • serverConnectionHandlerID

    ID of the server connection handler from which the voice data was sent.

  • clientID

    ID of the client whose voice data is received.

  • samples

    Pointer to the voice data (signed 16 bit @ 48KHz).

  • sampleCount

    Number of samples the "samples" variable points to.

  • channels

    Number of channels in the sound data.

  • channelSpeakerArray

    An array with channels entries, defining the speaker each channels represents. The speaker values can be found in the SPEAKER_* defines within public_definitions.h.

    For example for stereo (channels = 2), the array might look liks this: -

    channelSpeakerArray[0] = SPEAKER_FRONT_LEFT
    -channelSpeakerArray[1] = SPEAKER_FRONT_RIGHT
  • channelFillMask

    A pointer to a bit-mask defining which channels are filled. For efficiency reasons, not all channels need to have actual sound data in it. So before this data is used, use this bit-mask to check if the channel is actually filled. If you decide to add data to a channel that is empty, set the bit for this channel in this mask.

For example, this callback reports:

channels = 6
-channelSpeakerArray[0] = SPEAKER_FRONT_CENTER
-channelSpeakerArray[1] = SPEAKER_LOW_FREQUENCY
-channelSpeakerArray[2] = SPEAKER_BACK_LEFT
-channelSpeakerArray[3] = SPEAKER_BACK_RIGHT
-channelSpeakerArray[4] = SPEAKER_SIDE_LEFT
-channelSpeakerArray[5] = SPEAKER_SIDE_RIGHT  // Quite unusual setup
-*channelFillMask = 1

This means "samples" points to 6 channel data, but only the SPEAKER_FRONT_CENTER channel has data, the other channels are undefined (not necessarily 0, but undefined).

So for the first sample, samples[0] has data and samples[1], samples[2], samples[3], samples[4] and samples[5] are undefined.

If you want to add SPEAKER_BACK_RIGHT channel data you would do something like:

*channelFillMask |= 1<<3;  // SPEAKER_BACK_RIGHT is the 4th channel (is index 3) according to *channelSpeakerArray.
-for(int i=0; i<sampleCount; ++i){
-    samples[3 + (i*channels) ] = getChannelSoundData(SPEAKER_BACK_RIGHT, i); 
-}


-

The following event is called when all sounds that are about to be played back for this server connection are mixed. This is the last chance to alter/get sound.

You can use this function to alter/get the sound data before playback.

void onEditMixedPlaybackVoiceDataEvent(serverConnectionHandlerID,  
 samples,  
 sampleCount,  
 channels,  
 channelSpeakerArray,  
 channelFillMask); 
uint64 serverConnectionHandlerID;
short* samples;
int sampleCount;
int channels;
const unsigned int* channelSpeakerArray;
unsigned int* channelFillMask;
 
  • serverConnectionHandlerID

    ID of the server connection handler from which the voice data was sent.

  • samples

    Pointer to the voice data (signed 16 bit @ 48KHz).

  • sampleCount

    Number of samples the "samples" variable points to.

  • channels

    Number of channels in the sound data.

  • channelSpeakerArray

    An array with channels entries, defining the speaker each channels represents. The speaker values can be found in the SPEAKER_* defines within public_definitions.h.

    For example for stereo (channels = 2), the array might look liks this: -

    channelSpeakerArray[0] = SPEAKER_FRONT_LEFT
    -channelSpeakerArray[1] = SPEAKER_FRONT_RIGHT
  • channelFillMask

    A pointer to a bit-mask of which channels are filled. For efficiency reasons, not all channels need to have actual sound data in it. So before this data is used, use this bit-mask to check if the channel is actually filled. If you decide to add data to a channel that is empty, set the bit for this channel in this mask.


-

The following event is called after sound is recorded from the sound device and is preprocessed. This event can be used to get/alter recorded sound. Also it can be determined if this sound will be send, or muted. This is used by the TeamSpeak client to record sessions.

If the sound data will be send, (*edited | 2) is true. If the sound data is changed, set bit 1 (*edited |=1). If the sound should not be send, clear bit 2. (*edited &= ~2)

void onEditCapturedVoiceDataEvent(serverConnectionHandlerID,  
 samples,  
 sampleCount,  
 channels,  
 edited); 
uint64 serverConnectionHandlerID;
short* samples;
int sampleCount;
int channels;
int* edited;
 
  • serverConnectionHandlerID

    ID of the server connection handler from which the voice data was sent.

  • samples

    Pointer to the voice data (signed 16 bit @ 48KHz).

  • sampleCount

    Number of samples the "samples" variable points to.

  • channels

    Number of channels in the sound data.

  • edited

    When called, bit 2 indicates if the sound is about to be sent to the server.

    On return, set bit 1 if the sound data was changed.

Voice recording

When using the above callbacks to record voice, you should notify the server when recording starts or stops with the following functions:

unsigned int ts3client_startVoiceRecording(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 
unsigned int ts3client_stopVoiceRecording(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which voice recording should be started or stopped.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

diff --git a/pluginsdk/docs/client_html/ar01s19.html b/pluginsdk/docs/client_html/ar01s19.html deleted file mode 100644 index 494d725..0000000 --- a/pluginsdk/docs/client_html/ar01s19.html +++ /dev/null @@ -1,13 +0,0 @@ -Playing wave files

Playing wave files

The TeamSpeak Client Lib offers support to play wave files from the local harddisk.

To play a local wave file, call -

unsigned int ts3client_playWaveFile(serverConnectionHandlerID,  
 path); 
anyID serverConnectionHandlerID;
const char* path;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler defining which playback device is to be used to play the sound file.

  • path

    Local filepath of the sound file in WAV format to be played, encoded in UTF-8.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

This is the simple version of playing a sound file. It's a fire-and-forget mechanism, this function will not block.


-

The more complex version is to play an optionally looping sound and obtain a handle, which can be used to pause, unpause and stop the loop. -

unsigned int ts3client_playWaveFileHandle(serverConnectionHandlerID,  
 path,  
 loop,  
 waveHandle); 
anyID serverConnectionHandlerID;
const char* path;
int loop;
uint64* waveHandle;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler defining which playback device is to be used to play the sound file.

  • path

    Local filepath of the sound file in WAV format to be played, encoded in UTF-8.

  • loop

    If set to 1, the sound will be looping until the handle is paused or closed.

  • waveHandle

    Memory address of a variable in which the handle is written. Use this handle to call ts3client_pauseWaveFileHandle and ts3client_closeWaveFileHandle.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error occured, waveHandle is uninitialized and must not be used.


-

Using the handle obtained by ts3client_playWaveFileHandle, sounds can be paused and unpaused with -

unsigned int ts3client_pauseWaveFileHandle(serverConnectionHandlerID,  
 waveHandle,  
 pause); 
anyID serverConnectionHandlerID;
uint64 waveHandle;
int pause;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler defining which playback device is to be used to play the sound file.

  • waveHandle

    Wave handle obtained by ts3client_playWaveFileHandle.

  • pause

    If set to 1, the sound will be paused. Set to 0 to unpause.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

Using the handle obtained by ts3client_playWaveFileHandle, sounds can be closed with -

unsigned int ts3client_closeWaveFileHandle(serverConnectionHandlerID,  
 waveHandle); 
anyID serverConnectionHandlerID;
uint64 waveHandle;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler defining which playback device is to be used to play the sound file.

  • waveHandle

    Wave handle obtained by ts3client_playWaveFileHandle.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

diff --git a/pluginsdk/docs/client_html/ar01s20.html b/pluginsdk/docs/client_html/ar01s20.html deleted file mode 100644 index 195c31e..0000000 --- a/pluginsdk/docs/client_html/ar01s20.html +++ /dev/null @@ -1,16 +0,0 @@ -3D Sound

3D Sound

TeamSpeak 3 supports 3D sound to assign each speaker a unique position in 3D space. Provided are functions to modify the 3D position, velocity and orientation of own and foreign clients.

Generally the struct TS3_VECTOR describes a vector in 3D space:

typedef struct {
-    float x;        /* X coordinate in 3D space. */
-    float y;        /* Y coordinate in 3D space. */
-    float z;        /* Z coordinate in 3D space. */
-} TS3_VECTOR;

To set the position, velocity and orientation of the own client in 3D space, call: -

unsigned int ts3client_systemset3DListenerAttributes(serverConnectionHandlerID,  
 position,  
 forward,  
 up); 
uint64 serverConnectionHandlerID;
const TS3_VECTOR* position;
const TS3_VECTOR* forward;
const TS3_VECTOR* up;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the 3D sound listener attributes are to be set.

  • position

    3D position of the own client.

    If passing NULL, the parameter is ignored and the value not updated.

  • forward

    Forward orientation of the listener. The vector must be of unit length and perpendicular to the up vector.

    If passing NULL, the parameter is ignored and the value not updated.

  • up

    Upward orientation of the listener. The vector must be of unit length and perpendicular to the forward vector.

    If passing NULL, the parameter is ignored and the value not updated.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

To adjust 3D sound system settings use: -

unsigned int ts3client_systemset3DSettings(serverConnectionHandlerID,  
 distanceFactor,  
 rolloffScale); 
uint64 serverConnectionHandlerID;
float distanceFactor;
float rolloffScale;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the 3D sound system settings are to be adjusted.

  • distanceFactor

    Relative distance factor. Default is 1.0 = 1 meter

  • rolloffScale

    Scaling factor for 3D sound rolloff. Defines how fast sound volume will attenuate. As higher the value, as faster the sound is toned with increasing distance.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

To adjust a clients position and velocity in 3D space, call: -

unsigned int ts3client_channelset3DAttributes(serverConnectionHandlerID,  
 clientID,  
 position); 
uint64 serverConnectionHandlerID;
anyID clientID;
const TS3_VECTOR* position;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the 3D sound channel attributes are to be adjusted.

  • clientID

    ID of the client to adjust.

  • position

    Vector specifying the position of the given client in 3D space.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

The following event is called to calculate volume attenuation for distance in 3D positioning of clients.

void onCustom3dRolloffCalculationClientEvent(serverConnectionHandlerID,  
 clientID,  
 distance,  
 volume); 
uint64 serverConnectionHandlerID;
anyID clientID;
float distance;
float* volume;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the volume attenuation calculation occured.

  • clientID

    ID of the client which is being 3D positioned.

  • distance

    The distance between the listener and the client.

  • volume

    The volume which the Client Lib calculated. This can be changed in this callback.


-

The following event is called to calculate volume attenuation for distance in 3D positioning of a wave file that was opened previously with ts3client_playWaveFileHandle.

void onCustom3dRolloffCalculationWaveEvent(serverConnectionHandlerID,  
 waveHandle,  
 distance,  
 volume); 
uint64 serverConnectionHandlerID;
uint64 waveHandle;
float distance;
float* volume;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the volume attenuation calculation occured.

  • waveHandle

    Handle for the playing wave file, returned by ts3client_playWaveFileHandle.

  • distance

    The distance between the listener and the client.

  • volume

    The volume which the Client Lib calculated. This can be changed in this callback.


-

This method is used to 3D position a wave file that was opened previously with ts3client_playWaveFileHandle.

unsigned int ts3client_set3DWaveAttributes(serverConnectionHandlerID,  
 waveHandle,  
 position); 
uint64 serverConnectionHandlerID;
uint64 waveHandle;
const TS3_VECTOR* position;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the volume attenuation calculation occured.

  • waveHandle

    Handle for the playing wave file, returned by ts3client_playWaveFileHandle.

  • position

    The 3D position of the sound.

  • volume

    The volume which the Client Lib calculated. This can be changed in this callback.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

diff --git a/pluginsdk/docs/client_html/ar01s21.html b/pluginsdk/docs/client_html/ar01s21.html deleted file mode 100644 index 4d89ab6..0000000 --- a/pluginsdk/docs/client_html/ar01s21.html +++ /dev/null @@ -1,41 +0,0 @@ -Query available servers, channels and clients

Query available servers, channels and clients

A client can connect to multiple servers. To list all currently existing server connection handlers, call: -

unsigned int ts3client_getServerConnectionHandlerList(result); 
uint64** result;
 

-

  • result

    Address of a variable that receives a NULL-termianted array of all currently existing server connection handler IDs. Unless an error occurs, the array must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the result array is uninitialized and must not be released.


-

A list of all channels on the specified virtual server can be queried with: -

unsigned int ts3client_getChannelList(serverConnectionHandlerID,  
 result); 
uint64 serverConnectionHandlerID;
uint64** result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the list of channels is requested.

  • result

    Address of a variable that receives a NULL-termianted array of channel IDs. Unless an error occurs, the array must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the result array is uninitialized and must not be released.


-

To get a list of all currently visible clients on the specified virtual server: -

unsigned intts3client_getClientList(serverConnectionHandlerID,  
 result); 
uint64 serverConnectionHandlerID;
anyID** result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the list of clients is requested.

  • result

    Address of a variable that receives a NULL-termianted array of client IDs. Unless an error occurs, the array must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the result array is uninitialized and must not be released.


-

To get a list of all clients in the specified channel if the channel is currently subscribed: -

unsigned int ts3client_getChannelClientList(serverConnectionHandlerID,  
 channelID,  
 result); 
uint64 serverConnectionHandlerID;
uint64 channelID;
anyID** result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the list of clients within the given channel is requested.

  • channelID

    ID of the channel whose client list is requested.

  • result

    Address of a variable that receives a NULL-termianted array of client IDs. Unless an error occurs, the array must be released using ts3client_freeMemory.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. If an error has occured, the result array is uninitialized and must not be released.


-

To query the channel ID the specified client has currently joined: -

unsigned int ts3client_getChannelOfClient(serverConnectionHandlerID,  
 clientID,  
 result); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the channel ID is requested.

  • clientID

    ID of the client whose channel ID is requested.

  • result

    Address of a variable that receives the ID of the channel the specified client has currently joined.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

To get the parent channel of a given channel: -

unsigned int ts3client_getParentChannelOfChannel(serverConnectionHandlerID,  
 channelID,  
 result); 
uint64 serverConnectionHandlerID;
uint64 channelID;
uint64* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the parent channel of the specified channel is requested.

  • channelID

    ID of the channel whose parent channel ID is requested.

  • result

    Address of a variable that receives the ID of the parent channel of the specified channel.

    If the specified channel has no parent channel, result will be set to the reserved channel ID 0.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

Example code to print a list of all channels on a virtual server:

uint64* channels;
-
-if(ts3client_getChannelList(serverID, &channels) == ERROR_ok) {
-    for(int i=0; channels[i] != NULL; i++) {
-        printf("Channel ID: %u\n", channels[i]);
-    }
-    ts3client_freeMemory(channels);
-}

To print all visible clients:

anyID* clients;
-
-if(ts3client_getClientList(scHandlerID, &clients) == ERROR_ok) {
-    for(int i=0; clients[i] != NULL; i++) {
-        printf("Client ID: %u\n", clients[i]);
-    }
-    ts3client_freeMemory(clients);
-}

Example to print all clients who are member of channel with ID 123:

uint64 channelID = 123;  /* Channel ID in this example */
-anyID *clients;
-
-if(ts3client_getChannelClientList(scHandlerID, channelID) == ERROR_ok) {
-    for(int i=0; clients[i] != NULL; i++) {
-        printf("Client ID: %u\n", clients[i]);
-    }
-    ts3client_freeMemory(clients);
-}
diff --git a/pluginsdk/docs/client_html/ar01s22.html b/pluginsdk/docs/client_html/ar01s22.html deleted file mode 100644 index ac7dcef..0000000 --- a/pluginsdk/docs/client_html/ar01s22.html +++ /dev/null @@ -1,143 +0,0 @@ -Retrieve and store information

Retrieve and store information

The Client Lib remembers a lot of information which have been passed through previously. The data is available to be queried by a client for convinience, so the interface code doesn't need to store the same information as well. The client can in many cases also modify the stored information for further processing by the server.

All strings passed to and from the Client Lib need to be encoded in UTF-8 format.

Client information

Information related to own client

Once connection to a TeamSpeak 3 server has been established, a unique client ID is assigned by the server. This ID can be queried with -

unsigned int ts3client_getClientID(serverConnectionHandlerID,  
 result); 
uint64 serverConnectionHandlerID;
anyID* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which we are querying the own client ID.

  • result

    Address of a variable that receives the client ID. Client IDs start with the value 1.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

Various information related about the own client can be checked with:

- -

unsigned int ts3client_getClientSelfVariableAsInt(serverConnectionHandlerID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
ClientProperties flag;
int* result;
 

- -

-

unsigned int ts3client_getClientSelfVariableAsString(serverConnectionHandlerID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
ClientProperties flag;
char** result;
 

- -

  • serverConnectionHandlerID

    ID of the server connection handler on which the information for the own client is requested.

  • flag

    Client propery to query, see below.

  • result

    Address of a variable which receives the result value as int or string, depending on which function is used. In case of a string, memory must be released using ts3client_freeMemory, unless an error occured.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. For the string version: If an error has occured, the result string is uninitialized and must not be released.

The parameter flag specifies the type of queried information. It is defined by the enum ClientProperties:

enum ClientProperties {
-  CLIENT_UNIQUE_IDENTIFIER = 0,   //automatically up-to-date for any client "in view", can be used
-                                  //to identify this particular client installation
-  CLIENT_NICKNAME,                //automatically up-to-date for any client "in view"
-  CLIENT_VERSION,                 //for other clients than ourself, this needs to be requested
-                                  //(=> requestClientVariables)
-  CLIENT_PLATFORM,                //for other clients than ourself, this needs to be requested
-                                  //(=> requestClientVariables)
-  CLIENT_FLAG_TALKING,            //automatically up-to-date for any client that can be heard
-                                  //(in room / whisper)
-  CLIENT_INPUT_MUTED,             //automatically up-to-date for any client "in view", this clients
-                                  //microphone mute status
-  CLIENT_OUTPUT_MUTED,            //automatically up-to-date for any client "in view", this clients
-                                  //headphones/speakers mute status
-  CLIENT_OUTPUTONLY_MUTED         //automatically up-to-date for any client "in view", this clients
-                                  //headphones/speakers only mute status
-  CLIENT_INPUT_HARDWARE,          //automatically up-to-date for any client "in view", this clients
-                                  //microphone hardware status (is the capture device opened?)
-  CLIENT_OUTPUT_HARDWARE,         //automatically up-to-date for any client "in view", this clients
-                                  //headphone/speakers hardware status (is the playback device opened?)
-  CLIENT_INPUT_DEACTIVATED,       //only usable for ourself, not propagated to the network
-  CLIENT_IDLE_TIME,               //internal use
-  CLIENT_DEFAULT_CHANNEL,         //only usable for ourself, the default channel we used to connect
-                                  //on our last connection attempt
-  CLIENT_DEFAULT_CHANNEL_PASSWORD,//internal use
-  CLIENT_SERVER_PASSWORD,         //internal use
-  CLIENT_META_DATA,               //automatically up-to-date for any client "in view", not used by
-                                  //TeamSpeak, free storage for sdk users
-  CLIENT_IS_MUTED,                //only make sense on the client side locally, "1" if this client is
-                                  //currently muted by us, "0" if he is not
-  CLIENT_IS_RECORDING,            //automatically up-to-date for any client "in view"
-  CLIENT_VOLUME_MODIFICATOR,      //internal use
-  CLIENT_VERSION_SIGN,			  //internal use
-  CLIENT_SECURITY_HASH,           //SDK only: Hash is provided by an outside source. A channel will
-                                  //use the security salt + other client data to calculate a hash,
-								  //which must be the same as the one provided here.
-  CLIENT_ENCRYPTION_CIPHERS,      //SDK only: list of available ciphers send to the server 
-  CLIENT_ENDMARKER,
-};
  • CLIENT_UNIQUE_IDENTIFIER

    String: Unique ID for this client. Stays the same after restarting the application, so you can use this to identify individual users.

  • CLIENT_NICKNAME

    Nickname used by the client. This value is always automatically updated for visible clients.

  • CLIENT_VERSION

    Application version used by this client. Needs to be requested with ts3client_requestClientVariables unless called on own client.

  • CLIENT_PLATFORM

    Operating system used by this client. Needs to be requested with ts3client_requestClientVariables unless called on own client.

  • CLIENT_FLAG_TALKING

    Set when the client is currently sending voice data to the server. Always available for visible clients.

    Note: You should query this flag for the own client using ts3client_getClientSelfVariableAsInt.

  • CLIENT_INPUT_MUTED

    Indicates the mute status of the clients capture device. Possible values are defined by the enum MuteInputStatus. Always available for visible clients.

  • CLIENT_OUTPUT_MUTED

    Indicates the combined mute status of the clients playback and capture devices. Possible values are defined by the enum MuteOutputStatus. Always available for visible clients.

  • CLIENT_OUTPUTONLY_MUTED

    Indicates the mute status of the clients playback device. Possible values are defined by the enum MuteOutputStatus. Always available for visible clients.

  • CLIENT_INPUT_HARDWARE

    Set if the clients capture device is not available. Possible values are defined by the enum HardwareInputStatus. Always available for visible clients.

  • CLIENT_OUTPUT_HARDWARE

    Set if the clients playback device is not available. Possible values are defined by the enum HardwareOutputStatus. Always available for visible clients.

  • CLIENT_INPUT_DEACTIVATED

    Set when the capture device has been deactivated as used in Push-To-Talk. Possible values are defined by the enum InputDeactivationStatus. Only used for the own clients and not available for other clients as it doesn't get propagated to the server.

  • CLIENT_IDLE_TIME

    Time the client has been idle. Needs to be requested with ts3client_requestClientVariables.

  • CLIENT_DEFAULT_CHANNEL

    CLIENT_DEFAULT_CHANNEL_PASSWORD

    Default channel name and password used in the last ts3client_startConnection call. Only available for own client.

  • CLIENT_META_DATA

    Not used by TeamSpeak 3, offers free storage for SDK users. Always available for visible clients.

  • CLIENT_IS_MUTED

    Indicates a client has been locally muted with ts3client_requestMuteClients. Client-side only.

  • CLIENT_IS_RECORDING

    Indicates a client is currently recording all voice data in his channel.

  • CLIENT_VOLUME_MODIFICATOR

    The client volume modifier set by ts3client_setClientVolumeModifier.

  • CLIENT_SECURITY_HASH

    Contains client security hash (optional feature). This hash is used to check if this client is allowed to enter specified channels with a matching CHANNEL_SECURITY_SALT. Motivation is to enforce clients joining a server with the specific identity, nickname and metadata.

    Please see the chapter “Security salts and hashes” in the Server SDK documentation for details.

  • CLIENT_ENCRYPTION_CIPHERS

    Comma-separated list of ciphers offered to the server to pick one from.

    Possible values are: -

    -           "AES-128"
    -           "AES-256"
    -       

    -

    Defaults to "AES-256,AES-128".


-

Generally all types of information can be retrieved as both string or integer. However, in most cases the expected data type is obvious, like querying CLIENT_NICKNAME will clearly require to store the result as string.

Example 1: Query client nickname

char* nickname;
-
-if(ts3client_getClientSelfVariableAsString(scHandlerID, CLIENT_NICKNAME, &nickname) == ERROR_ok) {
-    printf("My nickname is: %s\n", s);
-    ts3client_freeMemory(s);
-}

Example 2: Check if own client is currently talking (to be exact: sending voice data)

int talking;
-
-if(ts3client_getClientSelfVariableAsInt(scHandlerID, CLIENT_FLAG_TALKING, &talking) == ERROR_ok) {
-    switch(talking) {
-        case STATUS_TALKING:
-            // I am currently talking
-        break;
-        case STATUS_NOT_TALKING:
-            // I am currently not talking
-            break;
-        case STATUS_TALKING_WHILE_DISABLED:
-            // I am talking while microphone is disabled
-            break;
-        default:
-            printf("Invalid value for CLIENT_FLAG_TALKING\n");
-    }
-}


-

Information related to the own client can be modified with - -

unsigned int ts3client_setClientSelfVariableAsInt(serverConnectionHandlerID,  
 flag,  
 value); 
uint64 serverConnectionHandlerID;
ClientProperties flag;
int value;
 

- -

unsigned int ts3client_setClientSelfVariableAsString(serverConnectionHandlerID,  
 flag,  
 value); 
uint64 serverConnectionHandlerID;
ClientProperties flag;
const char* value;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the information for the own client is changed.

  • flag

    Client propery to query, see above.

  • value

    Value the client property should be changed to.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

[Important]Important

After modifying one or more client variables, you must flush the changes. Flushing ensures the changes are sent to the TeamSpeak 3 server.

unsigned int ts3client_flushClientSelfUpdates(serverConnectionHandlerID,  
 returnCode); 
uint64 serverConnectionHandlerID;
const char* returnCode;
 

The idea behind flushing is, one can modify multiple values by calling ts3client_setClientVariableAsString and ts3client_setClientVariableAsInt and then apply all changes in one step.

For example, to change the own nickname:

/* Modify data */
-if(ts3client_setClientSelfVariableAsString(scHandlerID, CLIENT_NICKNAME, "Joe") != ERROR_ok) {
-    printf("Error setting client variable\n");
-    return;
-}
-
-/* Flush changes */
-if(ts3client_flushClientSelfUpdates(scHandlerID, NULL) != ERROR_ok) {
-    printf("Error flushing client updates");
-}

Example for doing two changes:

/* Modify data 1 */
-if(ts3client_setClientSelfVariableAsInt(scHandlerID, CLIENT_AWAY, AWAY_ZZZ) != ERROR_ok) {
-    printf("Error setting away mode\n");
-    return;
-}
-
-/* Modify data 2 */
-if(ts3client_setClientSelfVariableAsString(scHandlerID, CLIENT_AWAY_MESSAGE, "Lunch") != ERROR_ok) {
-    printf("Error setting away message\n");
-    return;
-}
-
-/* Flush changes */
-if(ts3client_flushClientSelfUpdates(scHandlerID, NULL) != ERROR_ok) {
-    printf("Error flushing client updates");
-}

Example to mute and unmute the microphone:

unsigned int error;
-bool shouldTalk;
-
-shouldTalk = isPushToTalkButtonPressed();  // Your key detection implementation
-if((error = ts3client_setClientSelfVariableAsInt(scHandlerID, CLIENT_INPUT_DEACTIVATED,
-                                                 shouldTalk ? INPUT_ACTIVE : INPUT_DEACTIVATED)) != ERROR_ok) {
-    char* errorMsg;
-    if(ts3client_getErrorMessage(error, &errorMsg) != ERROR_ok) {
-        printf("Error toggling push-to-talk: %s\n", errorMsg);
-	ts3client_freeMemory(errorMsg);
-    }
-    return;
-}
-
-if(ts3client_flushClientSelfUpdates(scHandlerID, NULL) != ERROR_ok) {
-    char* errorMsg;
-    if(ts3client_getErrorMessage(error, &errorMsg) != ERROR_ok) {
-        printf("Error flushing after toggling push-to-talk: %s\n", errorMsg);
-	ts3client_freeMemory(errorMsg);
-    }
-}

See the FAQ section for further details on implementing Push-To-Talk with ts3client_setClientSelfVariableAsInt.

Information related to other clients

Information related to other clients can be retrieved in a similar way. Unlike own clients however, information cannot be modified.

To query client related information, use one of the following functions. The parameter flag is defined by the enum ClientProperties as shown above.

-

unsigned int ts3client_getClientVariableAsInt(serverConnectionHandlerID,  
 clientID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
anyID clientID;
ClientProperties flag;
int* result;
 

- -

-

unsigned int ts3client_getClientVariableAsUInt64(serverConnectionHandlerID,  
 clientID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
anyID clientID;
ClientProperties flag;
uint64* result;
 

- -

-

unsigned int ts3client_getClientVariableAsString(serverConnectionHandlerID,  
 clientID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
anyID clientID;
ClientProperties flag;
char** result;
 

- -

  • serverConnectionHandlerID

    ID of the server connection handler on which the information for the specified client is requested.

  • clientID

    ID of the client whose property is queried.

  • flag

    Client propery to query, see above.

  • result

    Address of a variable which receives the result value as int, uint64 or string, depending on which function is used. In case of a string, memory must be released using ts3client_freeMemory, unless an error occured.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. For the string version: If an error has occured, the result string is uninitialized and must not be released.


-

As the Client Lib cannot have all information for all users available all the time, the latest data for a given client can be requested from the server with: -

unsigned int ts3client_requestClientVariables(serverConnectionHandlerID,  
 clientID,  
 returnCode); 
uint64 serverConnectionHandlerID;
anyID clientID;
const char* returnCode;
 

-

The function requires one second delay before calling it again on the same client ID to avoid flooding the server.

  • serverConnectionHandlerID

    ID of the server connection handler on which the client variables are requested.

  • clientID

    ID of the client whose variables are requested.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

After requesting the information, the following event is called. This event is also called everytime a client variable has been changed: -

void onUpdateClientEvent(serverConnectionHandlerID,  
 clientID,  
 invokerID,  
 invokerName,  
 invokerUniqueIdentifier); 
uint64 serverConnectionHandlerID;
anyID clientID;
anyID invokerID;
const char* invokerName;
const char* invokerUniqueIdentifier;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the client variables are now available or have changed.

  • clientID

    ID of the client whose variables are now available or have changed.

  • invokerID

    ID of the client who edited this clients variables.

  • invokerName

    Nickname of the client who edited this clients variables.

  • invokerUniqueIdentifier

    Unique ID of the client who edited this clients variables.

The event does not carry the information per se, but now the Client Lib guarantees to have the clients information available, which can be subsequently queried with ts3client_getClientVariableAsInt and ts3client_getClientVariableAsString.

Whisper lists

A client with a whisper list set can talk to the specified clients and channels bypassing the standard rule that voice is only transmitted to the current channel. Whisper lists can be defined for individual clients. A whisper list consists of an array of client IDs and/or an array of channel IDs. -

unsigned int ts3client_requestClientSetWhisperList(serverConnectionHandlerID,  
 clientID,  
 targetChannelIDArray,  
 targetClientIDArray,  
 returnCode); 
uint64 serverConnectionHandlerID;
anyID clientID;
const uint64* targetChannelIDArray;
const anyID* targetClientIDArray;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the clients whisper list is modified.

  • clientID

    ID of the client whose whisper list is modified. If set to 0, the own client is modified (same as setting to own client ID).

  • targetChannelIDArray

    Array of channel IDs, terminated with 0. These channels will be added to the whisper list.

    To clear the list, pass NULL or an empty array.

  • targetClientIDArray

    Array of client IDs, terminated with 0. These clients will be added to the whisper list.

    To clear the list, pass NULL or an empty array.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

To disable the whisperlist for the given client, pass NULL to both targetChannelIDArray and targetClientIDArray. Careful: If you pass two empty arrays, whispering is not disabled but instead one would still be whispering to nobody (empty lists).

To control which client is allowed to whisper to own client, the Client Lib implements an internal whisper whitelist mechanism. When a client recieves a whisper while the whispering client has not yet been added to the whisper allow list, the receiving client gets the following event. Note that whisper voice data is not received until the sending client is added to the receivers whisper allow list.

void onIgnoredWhisperEvent(serverConnectionHandlerID,  
 clientID); 
uint64 serverConnectionHandlerID;
anyID clientID;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the event occured.

  • clientID

    ID of the whispering client.

The receiving client can decide to allow whispering from the sender and add the sending client to the whisper allow list by calling ts3client_allowWhispersFrom. If the sender is not added by the receiving client, this event persists being called but no voice data is transmitted to the receiving client.

To add a client to the whisper allow list:

unsigned int ts3client_allowWhispersFrom(serverConnectionHandlerID,  
 clID); 
uint64 serverConnectionHandlerID;
anyID clID;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the client should be added to the whisper allow list.

  • clID

    ID of the client to be added to the whisper allow list.

To remove a client from the whisper allow list:

unsigned int ts3client_removeFromAllowedWhispersFrom(serverConnectionHandlerID,  
 clID); 
uint64 serverConnectionHandlerID;
anyID clID;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the client should be removed from the whisper allow list.

  • clID

    ID of the client to be removed from the whisper allow list.

It won't have bad sideeffects if the same client ID is added to the whisper allow list multiple times.

diff --git a/pluginsdk/docs/client_html/ar01s22s02.html b/pluginsdk/docs/client_html/ar01s22s02.html deleted file mode 100644 index e005173..0000000 --- a/pluginsdk/docs/client_html/ar01s22s02.html +++ /dev/null @@ -1,75 +0,0 @@ -Channel information

Channel information

Querying and modifying information related to channels is similar to dealing with clients. The functions to query channel information are:

-

unsigned int ts3client_getChannelVariableAsInt(serverConnectionHandlerID,  
 channelID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
uint64 channelID;
ChannelProperties flag;
int* result;
 

- -

-

unsigned int ts3client_getChannelVariableAsUInt64(serverConnectionHandlerID,  
 channelID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
uint64 channelID;
ChannelProperties flag;
uint64* result;
 

- -

-

unsigned int ts3client_getChannelVariableAsString(serverConnectionHandlerID,  
 channelID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
uint64 channelID;
ChannelProperties flag;
char* result;
 

- -

  • serverConnectionHandlerID

    ID of the server connection handler on which the information for the specified channel is requested.

  • channelID

    ID of the channel whose property is queried.

  • flag

    Channel propery to query, see below.

  • result

    Address of a variable which receives the result value of type int, uint64 or string, depending on which function is used. In case of a string, memory must be released using ts3client_freeMemory, unless an error occured.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. For the string version: If an error has occured, the result string is uninitialized and must not be released.

The parameter flag specifies the type of queried information. It is defined by the enum ChannelProperties:

enum ChannelProperties {
-  CHANNEL_NAME = 0,             //Available for all channels that are "in view", always up-to-date
-  CHANNEL_TOPIC,                //Available for all channels that are "in view", always up-to-date
-  CHANNEL_DESCRIPTION,          //Must be requested (=> requestChannelDescription)
-  CHANNEL_PASSWORD,             //not available client side
-  CHANNEL_CODEC,                //Available for all channels that are "in view", always up-to-date
-  CHANNEL_CODEC_QUALITY,        //Available for all channels that are "in view", always up-to-date
-  CHANNEL_MAXCLIENTS,           //Available for all channels that are "in view", always up-to-date
-  CHANNEL_MAXFAMILYCLIENTS,     //Available for all channels that are "in view", always up-to-date
-  CHANNEL_ORDER,                //Available for all channels that are "in view", always up-to-date
-  CHANNEL_FLAG_PERMANENT,       //Available for all channels that are "in view", always up-to-date
-  CHANNEL_FLAG_SEMI_PERMANENT,  //Available for all channels that are "in view", always up-to-date
-  CHANNEL_FLAG_DEFAULT,         //Available for all channels that are "in view", always up-to-date
-  CHANNEL_FLAG_PASSWORD,        //Available for all channels that are "in view", always up-to-date
-  CHANNEL_CODEC_LATENCY_FACTOR, //Available for all channels that are "in view", always up-to-date
-  CHANNEL_CODEC_IS_UNENCRYPTED, //Available for all channels that are "in view", always up-to-date
-  CHANNEL_SECURITY_SALT,        //Sets the options+salt for security hash (SDK only)
-  CHANNEL_DELETE_DELAY,         //How many seconds to wait before deleting this channel
-  CHANNEL_ENDMARKER,
-};
  • CHANNEL_NAME

    String: Name of the channel.

  • CHANNEL_TOPIC

    String: Single-line channel topic.

  • CHANNEL_DESCRIPTION

    String: Optional channel description. Can have multiple lines. Clients need to request updating this variable for a specified channel using: -

    unsigned int ts3client_requestChannelDescription(serverConnectionHandlerID,  
     channelID,  
     returnCode); 
    uint64 serverConnectionHandlerID;
    uint64 channelID;
    const char* returnCode;
     

    - -

  • CHANNEL_PASSWORD

    String: Optional password for password-protected channels.

    [Note]Note

    Clients can only set this value, but not query it.

    If a password is set or removed by modifying this field, CHANNEL_FLAG_PASSWORD will be automatically adjusted.

  • CHANNEL_CODEC

    Int: Codec used for this channel:

    • 0 - Speex Narrowband (8 kHz)

    • 1 - Speex Wideband (16 kHz)

    • 2 - Speex Ultra-Wideband (32 kHz)

    • 3 - Celt (Mono, 48kHz)

    • 4 - Opus Voice (Mono, 48khz)

    • 5 - Opus Music (Stereo, 48khz)

    See Sound codecs.

  • CHANNEL_CODEC_QUALITY

    Int (0-10): Quality of channel codec of this channel. Valid values range from 0 to 10, default is 7. Higher values result in better speech quality but more bandwidth usage.

    See Encoder options.

  • CHANNEL_MAXCLIENTS

    Int: Number of maximum clients who can join this channel.

  • CHANNEL_MAXFAMILYCLIENTS

    Int: Number of maximum clients who can join this channel and all subchannels.

  • CHANNEL_ORDER

    Int: Defines how channels are sorted in the GUI. Channel order is the ID of the predecessor channel after which this channel is to be sorted. If 0, the channel is sorted at the top of its hirarchy.

    For more information please see the chapter Channel sorting.

  • CHANNEL_FLAG_PERMANENT / CHANNEL_FLAG_SEMI_PERMANENT

    Concerning channel durability, there are three types of channels:

    • Temporary

      Temporary channels have neither the CHANNEL_FLAG_PERMANENT nor CHANNEL_FLAG_SEMI_PERMANENT flag set. Temporary channels are automatically deleted by the server after the last user has left and the channel is empty. They will not be restored when the server restarts.

    • Semi-permanent / Permanent

      Semi-permanent and permanent channels are not automatically deleted when the last user left. As SDK servers are not persistant over restart, there is no effective difference between these two in the SDK.

  • CHANNEL_FLAG_DEFAULT

    Int (0/1): Channel is the default channel. There can only be one default channel per server. New users who did not configure a channel to join on login in ts3client_startConnection will automatically join the default channel.

  • CHANNEL_FLAG_PASSWORD

    Int (0/1): If set, channel is password protected. The password itself is stored in CHANNEL_PASSWORD.

  • CHANNEL_CODEC_LATENCY_FACTOR

    (Int: 1-10): Latency of this channel. This allows to increase the packet size resulting in less bandwidth usage at the cost of higher latency. A value of 1 (default) is the best setting for lowest latency and best quality. If bandwidth or network quality are restricted, increasing the latency factor can help stabilize the connection. Higher latency values are only possible for low-quality codec and codec quality settings.

    For best voice quality a low latency factor is recommended.

  • CHANNEL_CODEC_IS_UNENCRYPTED

    Int (0/1): If 1, this channel is not using encrypted voice data. If 0, voice data is encrypted for this channel. Note that channel voice data encryption can be globally disabled or enabled for the virtual server. Changing this flag makes only sense if global voice data encryption is set to be configured per channel as CODEC_ENCRYPTION_PER_CHANNEL (the default behaviour).

  • CHANNEL_SECURITY_SALT

    Contains the channels security salt (optional feature). When a client connects, the clients hash value in CLIENT_SECURITY_HASH is check against the channel salt to allow or deny the client to join this channel. Motivation is to enforce clients joining a server with the specific identity, nickname and metadata.

    Please see the chapter “Security salts and hashes” in the Server SDK documentation for details.

  • CHANNEL_DELETE_DELAY

    This parameter defines how many seconds the server waits until a temporary channel is deleted when empty.

    When a temporary channel is created, a timer is started. If a user joins the channel before the countdown is finished, the channel is not deleted. After the last person has left the channel, the countdown starts again. CHANNEL_DELETE_DELAY defines the length of this countdown in seconds.

    The time since the last client has left the temporary channel can be queried with ts3client_getChannelEmptySecs.


-

To modify channel data use

- -

unsigned int ts3client_setChannelVariableAsInt(serverConnectionHandlerID,  
 channelID,  
 flag,  
 value); 
uint64 serverConnectionHandlerID;
uint64 channelID;
ChannelProperties flag;
int value;
 

- -

- -

unsigned int ts3client_setChannelVariableAsUInt64(serverConnectionHandlerID,  
 channelID,  
 flag,  
 value); 
uint64 serverConnectionHandlerID;
uint64 channelID;
ChannelProperties flag;
uint64 value;
 

- -

- -

unsigned int ts3client_setChannelVariableAsString(serverConnectionHandlerID,  
 channelID,  
 flag,  
 value); 
uint64 serverConnectionHandlerID;
uint64 channelID;
ChannelProperties flag;
const char* value;
 

- -

  • serverConnectionHandlerID

    ID of the server connection handler on which the information for the specified channel should be changed.

  • channelID

    ID of the channel whoses property should be changed.

  • flag

    Channel propery to change, see above.

  • value

    Value the channel property should be changed to. Depending on which function is used, the value can be of type int, uint64 or string.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

[Important]Important

After modifying one or more channel variables, you have to flush the changes to the server. -

unsigned int ts3client_flushChannelUpdates(serverConnectionHandlerID,  
 channelID); 
uint64 serverConnectionHandlerID;
uint64 channelID;
 

-

As example, to change the channel name and topic:

/* Modify data 1 */
-if(ts3client_setChannelVariableAsString(scHandlerID, channelID, CHANNEL_NAME,
-                                        "Other channel name") != ERROR_ok) {
-    printf("Error setting channel name\n");
-    return;
-}
-
-/* Modify data 2 */
-if(ts3client_setChannelVariableAsString(scHandlerID, channelID, CHANNEL_TOPIC,
-                                        "Other channel topic") != ERROR_ok) {
-    printf("Error setting channel topic\n");
-    return;
-}
-
-/* Flush changes */
-if(ts3client_flushChannelUpdates(scHandlerID, channelID) != ERROR_ok) {
-    printf("Error flushing channel updates\n");
-    return;
-}


-

After a channel was edited using ts3client_setChannelVariableAsInt or ts3client_setChannelVariableAsString and the changes were flushed to the server, the edit is announced with the event:

void onUpdateChannelEditedEvent(serverConnectionHandlerID,  
 channelID,  
 invokerID,  
 invokerName,  
 invokerUniqueIdentifier); 
uint64 serverConnectionHandlerID;
uint64 channelID;
anyID invokerID;
const char* invokerName;
const char* invokerUniqueIdentifier;
 
  • serverConnectionHandlerID

    ID of the server connection handler on which the channel has been edited.

  • channelID

    ID of edited channel.

  • invokerID

    ID of the client who edited the channel.

  • invokerName

    String with the name of the client who edited the channel.

  • invokerUniqueIdentifier

    String with the unique ID of the client who edited the channel.


-

To find the channel ID from a channels path: -

unsigned int ts3client_getChannelIDFromChannelNames(serverConnectionHandlerID,  
 channelNameArray,  
 result); 
uint64 serverConnectionHandlerID;
char** channelNameArray;
uint64* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the channel ID is queried.

  • channelNameArray

    Array defining the position of the channel: "grandparent", "parent", "channel", "". The array is terminated by an empty string.

  • result

    Address of a variable which receives the queried channel ID.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

Channel voice data encryption

Voice data can be encrypted or unencrypted. Encryption will increase CPU load, so should be used only when required. Encryption can be configured per channel (the default) or globally enabled or disabled for the whole virtual server. By default channels are sending voice data unencrypted, newly created channels would need to be set to encrypted if required.

To configure the global virtual server encryption settings, modify the virtual server property VIRTUALSERVER_CODEC_ENCRYPTION_MODE to one of the following values: -

enum CodecEncryptionMode {
-   CODEC_ENCRYPTION_PER_CHANNEL = 0,  // Default
-   CODEC_ENCRYPTION_FORCED_OFF,
-   CODEC_ENCRYPTION_FORCED_ON,
-};

-

Voice data encryption per channel can be configured by setting the channel property CHANNEL_CODEC_IS_UNENCRYPTED to 0 (encrypted) or 1 (unencrypted) if global encryption mode is CODEC_ENCRYPTION_PER_CHANNEL. If encryption is forced on or off globally, the channel property will be automatically set by the server.

diff --git a/pluginsdk/docs/client_html/ar01s22s02s02.html b/pluginsdk/docs/client_html/ar01s22s02s02.html deleted file mode 100644 index 182f268..0000000 --- a/pluginsdk/docs/client_html/ar01s22s02s02.html +++ /dev/null @@ -1,7 +0,0 @@ -Channel sorting

Channel sorting

The order how channels should be display in the GUI is defined by the channel variable CHANNEL_ORDER, which can be queried with ts3client_getChannelVariableAsUInt64 or changed with ts3client_setChannelVariableAsUInt64.

The channel order is the ID of the predecessor channel after which the given channel should be sorted. An order of 0 means the channel is sorted on the top of its hirarchy.

Channel_1  (ID = 1, order = 0)
-Channel_2  (ID = 2, order = 1)
-      Subchannel_1  (ID = 4, order = 0)
-            Subsubchannel_1  (ID = 6, order = 0)
-            Subsubchannel_2  (ID = 7, order = 6)
-      Subchannel_2  (ID = 5, order = 4)
-Channel_3  (ID = 3, order = 2)

When a new channel is created, the client is responsible to set a proper channel order. With the default value of 0 the channel will be sorted on the top of its hirarchy right after its parent channel.

When moving a channel to a new parent, the desired channel order can be passed to ts3client_requestChannelMove.

To move the channel to another position within the current hirarchy - the parent channel stays the same -, adjust the CHANNEL_ORDER variable with ts3client_setChannelVariableAsUInt64.

After connecting to a TeamSpeak 3 server, the client will be informed of all channels by the onNewChannelEvent callback. The order how channels are propagated to the client by this event is:

  • First the complete channel path to the default channel, which is either the servers default channel with the flag CHANNEL_FLAG_DEFAULT or the users default channel passed to ts3client_startConnection. This ensures the channel joined on login is visible as soon as possible.

    In above example, assuming the default channel is “Subsubchannel_2”, the channels would be announced in the following order: Channel_2, Subchannel_1, Subsubchannel_2.

    After the default channel path has completely arrived, the connection status (see enum ConnectStatus, annouced to the client by the callback onConnectStatusChangeEvent) changes to STATUS_CONNECTION_ESTABLISHING.

  • Next all other channels in the given order, where subchannels are announced right after the parent channel.

    To continue the example, the remaining channels would be announced in the order of: Channel_1, Subsubchannel_1, Subchannel_2, Channel_3 (Channel_2, Subchannel_1, Subsubchannel_2 already were announced in the previous step).

    When all channels have arrived, the connection status switches to STATUS_CONNECTION_ESTABLISHED.

diff --git a/pluginsdk/docs/client_html/ar01s22s03.html b/pluginsdk/docs/client_html/ar01s22s03.html deleted file mode 100644 index 9a27987..0000000 --- a/pluginsdk/docs/client_html/ar01s22s03.html +++ /dev/null @@ -1,49 +0,0 @@ -Server information

Server information

Similar to reading client and channel data, server information can be queried with

- -

unsigned int ts3client_getServerVariableAsInt(serverConnectionHandlerID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
VirtualServerProperties flag;
int* result;
 

- -

-

unsigned int ts3client_getServerVariableAsUInt64(serverConnectionHandlerID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
VirtualServerProperties flag;
uint64* result;
 

- -

- -

unsigned int ts3client_getServerVariableAsString(serverConnectionHandlerID,  
 flag,  
 result); 
uint64 serverConnectionHandlerID;
VirtualServerProperties flag;
char** result;
 

- -

  • serverConnectionHandlerID

    ID of the server connection handler on which the virtual server property is queried.

  • clientID

    ID of the client whose property is queried.

  • flag

    Virtual server propery to query, see below.

  • result

    Address of a variable which receives the result value as int, uint64 or string, depending on which function is used. In case of a string, memory must be released using ts3client_freeMemory, unless an error occured.

    The returned type uint64 is defined as __int64 on Windows and uint64_t on Linux and Mac OS X. See the header public_definitions.h. This function is currently only used for the flag VIRTUALSERVER_UPTIME.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h. For the string version: If an error has occured, the result string is uninitialized and must not be released.

The parameter flag specifies the type of queried information. It is defined by the enum VirtualServerProperties:

enum VirtualServerProperties {
-  VIRTUALSERVER_UNIQUE_IDENTIFIER = 0, //available when connected, can be used to identify this particular
-                                       //server installation
-  VIRTUALSERVER_NAME,                  //available and always up-to-date when connected
-  VIRTUALSERVER_WELCOMEMESSAGE,        //available when connected, not updated while connected
-  VIRTUALSERVER_PLATFORM,              //available when connected
-  VIRTUALSERVER_VERSION,               //available when connected
-  VIRTUALSERVER_MAXCLIENTS,            //only available on request (=> requestServerVariables), stores the
-                                       //maximum number of clients that may currently join the server
-  VIRTUALSERVER_PASSWORD,              //not available to clients, the server password
-  VIRTUALSERVER_CLIENTS_ONLINE,        //only available on request (=> requestServerVariables),
-  VIRTUALSERVER_CHANNELS_ONLINE,       //only available on request (=> requestServerVariables),
-  VIRTUALSERVER_CREATED,               //available when connected, stores the time when the server was created
-  VIRTUALSERVER_UPTIME,                //only available on request (=> requestServerVariables), the time
-                                       //since the server was started
-  VIRTUALSERVER_CODEC_ENCRYPTION_MODE, //available and always up-to-date when connected
-  VIRTUALSERVER_ENCRYPTION_CIPHERS,    //SDK only: list of ciphers that can be used for encryption
-  VIRTUALSERVER_ENDMARKER,
-};
  • VIRTUALSERVER_UNIQUE_IDENTIFIER

    Unique ID for this virtual server. Stays the same after restarting the server application. Always available when connected.

  • VIRTUALSERVER_NAME

    Name of this virtual server. Always available when connected.

  • VIRTUALSERVER_WELCOMEMESSAGE

    Optional welcome message sent to the client on login. This value should be queried by the client after connection has been established, it is not updated afterwards.

  • VIRTUALSERVER_PLATFORM

    Operating system used by this server. Always available when connected.

  • VIRTUALSERVER_VERSION

    Application version of this server. Always available when connected.

  • VIRTUALSERVER_MAXCLIENTS

    Defines maximum number of clients which may connect to this server. Needs to be requested using ts3client_requestServerVariables.

  • VIRTUALSERVER_PASSWORD

    Optional password of this server. Not available to clients.

  • VIRTUALSERVER_CLIENTS_ONLINE

    VIRTUALSERVER_CHANNELS_ONLINE

    Number of clients and channels currently on this virtual server. Needs to be requested using ts3client_requestServerVariables.

  • VIRTUALSERVER_CREATED

    Time when this virtual server was created. Always available when connected.

  • VIRTUALSERVER_UPTIME

    Uptime of this virtual server. Needs to be requested using ts3client_requestServerVariables.

  • VIRTUALSERVER_CODEC_ENCRYPTION_MODE

    Defines if voice data encryption is configured per channel, globally forced on or globally forced off for this virtual server. The default behaviour is configure per channel, in this case modifying the channel property CHANNEL_CODEC_IS_UNENCRYPTED defines voice data encryption of individual channels.

    Virtual server encryption mode can be set to the following parameters: -

    enum CodecEncryptionMode {
    -   CODEC_ENCRYPTION_PER_CHANNEL = 0,
    -   CODEC_ENCRYPTION_FORCED_OFF,
    -   CODEC_ENCRYPTION_FORCED_ON,
    -};

    -

    This property is always available when connected.


-

Example code checking the number of clients online, obviously an integer value: -

int clientsOnline;
-
-if(ts3client_getServerVariableAsInt(scHandlerID, VIRTUALSERVER_CLIENTS_ONLINE, &clientsOnline) == ERROR_ok)
-    printf("There are %d clients online\n", clientsOnline);


-

A client can request refreshing the server information with: -

unsigned int ts3client_requestServerVariables(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-

The following event informs the client when the requested information is available: -

unsigned int onServerUpdatedEvent(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-


-

The following event notifies the client when virtual server information has been edited: -

void onServerEditedEvent(serverConnectionHandlerID,  
 editerID,  
 editerName,  
 editerUniqueIdentifier); 
uint64 serverConnectionHandlerID;
anyID editerID;
const char* editerName;
const char* editerUniqueIdentifier;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler which virtual server information has been changed.

  • editerID

    ID of the client who edited the information. If zero, the server is the editor.

  • editerName

    Name of the client who edited the information.

  • editerUniqueIdentifier

    Unique ID of the client who edited the information.

diff --git a/pluginsdk/docs/client_html/ar01s23.html b/pluginsdk/docs/client_html/ar01s23.html deleted file mode 100644 index 0350c3b..0000000 --- a/pluginsdk/docs/client_html/ar01s23.html +++ /dev/null @@ -1,27 +0,0 @@ -Interacting with the server

Interacting with the server

Interacting with the server means various actions, related to both channels and clients. Channels can be joined, created, edited, deleted and subscribed. Clients can use text chat with other clients, be kicked or poked and move between channels.

All strings passed to and from the Client Lib need to be encoded in UTF-8 format.

Joining a channel

When a client logs on to a TeamSpeak 3 server, he will automatically join the channel with the “Default” flag, unless he specified another channel in ts3client_startConnection. To have your own or another client switch to a certain channel, call -

unsigned int ts3client_requestClientMove(serverConnectionHandlerID,  
 clientID,  
 newChannelID,  
 password,  
 returnCode); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64 newChannelID;
const char* password;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler ID on which this action is requested.

  • clientID

    ID of the client to move.

  • newChannelID

    ID of the channel the client wants to join.

  • password

    An optional password, required for password-protected channels. Pass an empty string if no password is given.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

If the move was successful, one the following events will be called: - -

void onClientMoveEvent(serverConnectionHandlerID,  
 clientID,  
 oldChannelID,  
 newChannelID,  
 visibility,  
 moveMessage); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64 oldChannelID;
uint64 newChannelID;
int visibility;
const char* moveMessage;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the action occured.

  • clientID

    ID of the moved client.

  • oldChannelID

    ID of the old channel left by the client.

  • newChannelID

    ID of the new channel joined by the client.

  • visibility

    Defined in the enum Visibility - -

    enum Visibility {
    -    ENTER_VISIBILITY = 0,
    -    RETAIN_VISIBILITY,
    -    LEAVE_VISIBILITY
    -};

    -

    • ENTER_VISIBILITY

      Client moved and entered visibility. Cannot happen on own client.

    • RETAIN_VISIBILITY

      Client moved between two known places. Can happen on own or other client.

    • LEAVE_VISIBILITY

      Client moved out of our sight. Cannot happen on own client.

  • moveMessage

    When a client disconnects from the server, this includes the optional message set by the disconnecting client in ts3client_stopConnection.

Example: Requesting to move the own client into channel ID 12 (not password-protected):

ts3client_requestClientMove(scHandlerID, ts3client_getClientID(scHandlerID), 12, "", NULL);

Now wait for the callback:

-void my_onClientMoveEvent(uint64 scHandlerID, anyID clientID,
-                          uint64 oldChannelID, uint64 newChannelID,
-                          int visibility, const char* moveMessage) {
-  // scHandlerID   ->  Server connection handler ID, same as above when requesting
-  // clientID      ->  Own client ID, same as above when requesting
-  // oldChannelID  ->  ID of the channel the client has left
-  // newChannelID  ->  12, as requested above
-  // visibility    ->  One of ENTER_VISIBILITY, RETAIN_VISIBILITY, LEAVE_VISIBILITY
-  // moveMessage   ->  Optional message set by disconnecting clients
-}


-

If the move was initiated by another client, instead of onClientMove the following event is called: -

void onClientMoveMovedEvent(serverConnectionHandlerID,  
 clientID,  
 oldChannelID,  
 newChannelID,  
 visibility,  
 moverID,  
 moverName,  
 moverUniqueIdentifier,  
 moveMessage); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64 oldChannelID;
uint64 newChannelID;
int visibility;
anyID moverID;
const char* moverName;
const char* moverUniqueIdentifier;
const char* moveMessage;
 

-

Like onClientMoveEvent but with additional information about the client, which has initiated the move: moverID defines the ID, moverName the nickname and moverUniqueIdentifier the unique ID of the client who initiated the move. moveMessage contains a string giving the reason for the move.

If oldChannelID is 0, the client has just connected to the server. If newChannelID is 0, the client disconnected. Both values cannot be 0 at the same time.

diff --git a/pluginsdk/docs/client_html/ar01s23s02.html b/pluginsdk/docs/client_html/ar01s23s02.html deleted file mode 100644 index c156590..0000000 --- a/pluginsdk/docs/client_html/ar01s23s02.html +++ /dev/null @@ -1,36 +0,0 @@ -Creating a new channel

Creating a new channel

To create a channel, set the various channel variables using ts3client_setChannelVariableAsInt and ts3client_setChannelVariableAsString. Pass zero as the channel ID parameter.

Then flush the changes to the server by calling: -

unsigned int ts3client_flushChannelCreation(serverConnectionHandlerID,  
 channelParentID); 
uint64 serverConnectionHandlerID;
uint64 channelParentID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler to which the channel changes should be flushed.

  • channelParentID

    ID of the parent channel, if the new channel is to be created as subchannel. Pass zero if the channel should be created as top-level channel.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

After flushing the changes to the server, the following event will be called on successful channel creation: -

void onNewChannelCreatedEvent(serverConnectionHandlerID,  
 channelID,  
 channelParentID,  
 invokerID,  
 invokerName,  
 invokerUniqueIdentifier); 
uint64 serverConnectionHandlerID;
uint64 channelID;
uint64 channelParentID;
anyID invokerID;
const char* invokerName;
const char* invokerUniqueIdentifier;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler where the channel was created.

  • channelID

    ID of the created channel. Channel IDs start with the value 1.

  • channelParentID

    ID of the parent channel.

  • invokerID

    ID of the client who requested the creation. If zero, the request was initiated by the server.

  • invokerName

    Name of the client who requested the creation. If requested by the server, the name is empty.

  • invokerUniqueIdentifier

    Unique ID of the client who requested the creation.


-

Example code to create a channel:

#define CHECK_ERROR(x) if((error = x) != ERROR_ok) { goto on_error; }
-
-int createChannel(uint64 scHandlerID, uint64 parentChannelID, const char* name, const char* topic,
-                  const char* description, const char* password, int codec, int codecQuality,
-                  int maxClients, int familyMaxClients, int order, int perm,
-                  int semiperm, int default) {
-  unsigned int error;
-
-  /* Set channel data, pass 0 as channel ID */
-  CHECK_ERROR(ts3client_setChannelVariableAsString(scHandlerID, 0, CHANNEL_NAME, name));
-  CHECK_ERROR(ts3client_setChannelVariableAsString(scHandlerID, 0, CHANNEL_TOPIC, topic));
-  CHECK_ERROR(ts3client_setChannelVariableAsString(scHandlerID, 0, CHANNEL_DESCRIPTION, desc));
-  CHECK_ERROR(ts3client_setChannelVariableAsString(scHandlerID, 0, CHANNEL_PASSWORD, password));
-  CHECK_ERROR(ts3client_setChannelVariableAsInt   (scHandlerID, 0, CHANNEL_CODEC, codec));
-  CHECK_ERROR(ts3client_setChannelVariableAsInt   (scHandlerID, 0, CHANNEL_CODEC_QUALITY, codecQuality));
-  CHECK_ERROR(ts3client_setChannelVariableAsInt   (scHandlerID, 0, CHANNEL_MAXCLIENTS, maxClients));
-  CHECK_ERROR(ts3client_setChannelVariableAsInt   (scHandlerID, 0, CHANNEL_MAXFAMILYCLIENTS, familyMaxClients));
-  CHECK_ERROR(ts3client_setChannelVariableAsUInt64(scHandlerID, 0, CHANNEL_ORDER, order));
-  CHECK_ERROR(ts3client_setChannelVariableAsInt   (scHandlerID, 0, CHANNEL_FLAG_PERMANENT, perm));
-  CHECK_ERROR(ts3client_setChannelVariableAsInt   (scHandlerID, 0, CHANNEL_FLAG_SEMI_PERMANENT, semiperm));
-  CHECK_ERROR(ts3client_setChannelVariableAsInt   (scHandlerID, 0, CHANNEL_FLAG_DEFAULT, default));
-
-  /* Flush changes to server */
-  CHECK_ERROR(ts3client_flushChannelCreation(scHandlerID, parentChannelID));
-  return 0;  /* Success */
-
-on_error:
-  printf("Error creating channel: %d\n", error);
-  return 1;  /* Failure */
-}
diff --git a/pluginsdk/docs/client_html/ar01s23s03.html b/pluginsdk/docs/client_html/ar01s23s03.html deleted file mode 100644 index 7ca7087..0000000 --- a/pluginsdk/docs/client_html/ar01s23s03.html +++ /dev/null @@ -1,6 +0,0 @@ -Deleting a channel

Deleting a channel

A channel can be removed with -

unsigned int ts3client_requestChannelDelete(serverConnectionHandlerID,  
 channelID,  
 force,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
int force;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the channel should be deleted.

  • channelID

    The ID of the channel to be deleted.

  • force

    If 1, the channel will be deleted even when it is not empty. Clients within the deleted channel are transfered to the default channel. Any contained subchannels are removed as well.

    If 0, the server will refuse to delete a channel that is not empty.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

After the request has been sent to the server, the following event will be called: -

void onDelChannelEvent(serverConnectionHandlerID,  
 channelID,  
 invokerID,  
 invokerName,  
 invokerUniqueIdentifier); 
uint64 serverConnectionHandlerID;
uint64 channelID;
anyID invokerID;
const char* invokerName;
const char* invokerUniqueIdentifier;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the channel was deleted.

  • channelID

    The ID of the deleted channel.

  • invokerID

    The ID of the client who requested the deletion. If zero, the deletion was initiated by the server (for example automatic deletion of empty non-permanent channels).

  • invokerName

    The name of the client who requested the deletion. Empty if requested by the server.

  • invokerUniqueIdentifier

    The unique ID of the client who requested the deletion.

diff --git a/pluginsdk/docs/client_html/ar01s23s04.html b/pluginsdk/docs/client_html/ar01s23s04.html deleted file mode 100644 index 19c1a5c..0000000 --- a/pluginsdk/docs/client_html/ar01s23s04.html +++ /dev/null @@ -1,6 +0,0 @@ -Moving a channel

Moving a channel

To move a channel to a new parent channel, call -

unsigned int ts3client_requestChannelMove(serverConnectionHandlerID,  
 channelID,  
 newChannelParentID,  
 newChannelOrder,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
uint64 newChannelParentID;
uint64 newChannelOrder;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the channel should be moved.

  • channelID

    ID of the channel to be moved.

  • newChannelParentID

    ID of the parent channel where the moved channel is to be inserted as child. Use 0 to insert as top-level channel.

  • newChannelOrder

    Channel order defining where the channel should be sorted under the new parent. Pass 0 to sort the channel right after the parent. See the chapter Channel sorting for details.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

After sending the request, the following event will be called if the move was successful: -

void onChannelMoveEvent(serverConnectionHandlerID,  
 channelID,  
 newChannelParentID,  
 invokerID,  
 invokerName,  
 invokerUniqueIdentifier); 
uint64 serverConnectionHandlerID;
uint64 channelID;
uint64 newChannelParentID;
anyID invokerID;
const char* invokerName;
const char* invokerUniqueIdentifier;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the channel was moved.

  • channelID

    The ID of the moved channel.

  • newChannelParentID

    ID of the parent channel where the moved channel is inserted as child. 0 if inserted as top-level channel.

  • invokerID

    The ID of the client who requested the move. If zero, the move was initiated by the server.

  • invokerName

    The name of the client who requested the move. Empty if requested by the server.

  • invokerUniqueIdentifier

    The unique ID of the client who requested the move.

diff --git a/pluginsdk/docs/client_html/ar01s23s05.html b/pluginsdk/docs/client_html/ar01s23s05.html deleted file mode 100644 index 150ee9d..0000000 --- a/pluginsdk/docs/client_html/ar01s23s05.html +++ /dev/null @@ -1 +0,0 @@ -Text chat

Text chat

In addition to voice chat, TeamSpeak 3 allows clients to communicate with text-chat. Valid targets can be a client, channel or virtual server. Depending on the target, there are three functions to send text messages and one callback to receive them.

diff --git a/pluginsdk/docs/client_html/ar01s23s05s01.html b/pluginsdk/docs/client_html/ar01s23s05s01.html deleted file mode 100644 index f9f8b24..0000000 --- a/pluginsdk/docs/client_html/ar01s23s05s01.html +++ /dev/null @@ -1,15 +0,0 @@ -Sending

Sending

To send a private text message to a client: -

unsigned int ts3client_requestSendPrivateTextMsg(serverConnectionHandlerID,  
 message,  
 targetClientID,  
 returnCode); 
uint64 serverConnectionHandlerID;
const char* message;
anyID targetClientID;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    Id of the target server connection handler.

  • message

    String containing the text message

  • targetClientID

    Id of the target client.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

To send a text message to a channel: -

unsigned int ts3client_requestSendChannelTextMsg(serverConnectionHandlerID,  
 message,  
 targetChannelID,  
 returnCode); 
uint64 serverConnectionHandlerID;
const char* message;
anyID targetChannelID;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    Id of the target server connection handler.

  • message

    String containing the text message

  • targetChannelID

    Id of the target channel.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

To send a text message to the virtual server: -

unsigned int ts3client_requestSendServerTextMsg(serverConnectionHandlerID,  
 message,  
 returnCode); 
uint64 serverConnectionHandlerID;
const char* message;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    Id of the target server connection handler.

  • message

    String containing the text message

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

Example to send a text chat to a client with ID 123:

const char *msg = "Hello TeamSpeak!";
-anyID targetClientID = 123;
-
-if(ts3client_requestSendPrivateTextMsg(scHandlerID, msg, targetClient, NULL) != ERROR_ok) {
-  /* Handle error */
-}
diff --git a/pluginsdk/docs/client_html/ar01s23s05s02.html b/pluginsdk/docs/client_html/ar01s23s05s02.html deleted file mode 100644 index 22adf15..0000000 --- a/pluginsdk/docs/client_html/ar01s23s05s02.html +++ /dev/null @@ -1,8 +0,0 @@ -Receiving

Receiving

The following event will be called when a text message is received: -

void onTextMessageEvent(serverConnectionHandlerID,  
 targetMode,  
 toID,  
 fromID,  
 fromName,  
 fromUniqueIdentifier,  
 message); 
uint64 serverConnectionHandlerID;
anyID targetMode;
anyID toID;
anyID fromID;
const char* fromName;
const char* fromUniqueIdentifier;
const char* message;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler from which the text message was sent.

  • targetMode

    Target mode of this text message. The value is defined by the enum TextMessageTargetMode:

    enum TextMessageTargetMode {
    -    TextMessageTarget_CLIENT=1,
    -    TextMessageTarget_CHANNEL,
    -    TextMessageTarget_SERVER,
    -    TextMessageTarget_MAX
    -};
  • toID

    Id of the target of the text message.

  • fromID

    Id of the client who sent the text message.

  • fromName

    Name of the client who sent the text message.

  • fromUniqueIdentifier

    Unique ID of the client who sent the text message.

  • message

    String containing the text message.

diff --git a/pluginsdk/docs/client_html/ar01s23s06.html b/pluginsdk/docs/client_html/ar01s23s06.html deleted file mode 100644 index ed2da69..0000000 --- a/pluginsdk/docs/client_html/ar01s23s06.html +++ /dev/null @@ -1,14 +0,0 @@ -Kicking clients

Kicking clients

Clients can be forcefully removed from a channel or the whole server. To kick a client from a channel or server call:

-

unsigned int ts3client_requestClientKickFromChannel(serverConnectionHandlerID,  
 clientID,  
 kickReason,  
 returnCode); 
uint64 serverConnectionHandlerID;
anyID clientID;
const char* kickReason;
const char* returnCode;
 

- -

-

unsigned int ts3client_requestClientKickFromServer(serverConnectionHandlerID,  
 clientID,  
 kickReason,  
 returnCode); 
uint64 serverConnectionHandlerID;
anyID clientID;
const char* kickReason;
const char* returnCode;
 

- -

  • serverConnectionHandlerID

    Id of the target server connection.

  • clientID

    The ID of the client to be kicked.

  • kickReason

    A short message explaining why the client is kicked from the channel or server.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

After successfully requesting a kick, one of the following events will be called:

-

void onClientKickFromChannelEvent(serverConnectionHandlerID,  
 clientID,  
 oldChannelID,  
 newChannelID,  
 visibility,  
 kickerID,  
 kickerName,  
 kickerUniqueIdentifier,  
 kickMessage); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64 oldChannelID;
uint64 newChannelID;
int visibility;
anyID kickerID;
const char* kickerName;
const char* kickerUniqueIdentifier;
const char* kickMessage;
 

- -

-

void onClientKickFromServerEvent(serverConnectionHandlerID,  
 clientID,  
 oldChannelID,  
 newChannelID,  
 visibility,  
 kickerID,  
 kickerName,  
 kickerUniqueIdentifier,  
 kickMessage); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64 oldChannelID;
uint64 newChannelID;
int visibility;
anyID kickerID;
const char* kickerName;
const char* kickerUniqueIdentifier;
const char* kickMessage;
 

- -

  • serverConnectionHandlerID

    ID of the server connection handler on which the client was kicked

  • clientID

    ID of the kicked client.

  • oldChannelID

    ID of the channel from which the client has been kicked.

  • newChannelID

    ID of the channel where the kicked client was moved to.

  • visibility

    Describes if the moved client enters, retains or leaves visibility. See explanation of the enum Visibility for the function onClientMoveEvent.

    When kicked from a server, visibility can be only LEAVE_VISIBILITY.

  • kickerID

    ID of the client who requested the kick.

  • kickerName

    Name of the client who requested the kick.

  • kickerUniqueIdentifier

    Unique ID of the client who requested the kick.

  • kickerMessage

    Message giving the reason why the client has been kicked.

diff --git a/pluginsdk/docs/client_html/ar01s23s07.html b/pluginsdk/docs/client_html/ar01s23s07.html deleted file mode 100644 index da74b7c..0000000 --- a/pluginsdk/docs/client_html/ar01s23s07.html +++ /dev/null @@ -1,28 +0,0 @@ -Channel subscriptions

Channel subscriptions

Normally a user only sees other clients who are in the same channel. Clients joining or leaving other channels or changing status are not displayed. To offer a way to get notifications about clients in other channels, a user can subscribe to other channels. It would also be possible to always subscribe to all channels to get notifications about all clients on the server.

Subscriptions are meant to have a flexible way to balance bandwidth usage. On a crowded server limiting the number of subscribed channels is a way to reduce network traffic. Also subscriptions allow to usage “private” channels, whose members cannot be seen by other users.

[Note]Note

A client is automatically subscribed to the current channel.

To subscribe to a list of channels (zero-terminated array of channel IDs) call: -

unsigned int ts3client_requestChannelSubscribe(serverConnectionHandlerID,  
 channelIDArray,  
 returnCode); 
uint64 serverConnectionHandlerID;
const uint64* channelIDArray;
const char* returnCode;
 

-

To unsubscribe from a list of channels (zero-terminated array of channel IDs) call: -

unsigned int ts3client_requestChannelUnsubscribe(serverConnectionHandlerID,  
 channelIDArray,  
 returnCode); 
uint64 serverConnectionHandlerID;
const uint64* channelIDArray;
const char* returnCode;
 

-

To subscribe to all channels on the server call: -

unsigned int ts3client_requestChannelSubscribeAll(serverConnectionHandlerID,  
 returnCode); 
uint64 serverConnectionHandlerID;
const char* returnCode;
 

-

To unsubscribe from all channels on the server call: -

unsigned int ts3client_requestChannelUnsubscribeAll(serverConnectionHandlerID,  
 returnCode); 
uint64 serverConnectionHandlerID;
const char* returnCode;
 

-

To check if a channel is currently subscribed, check the channel property CHANNEL_FLAG_ARE_SUBSCRIBED with ts3client_getChannelVariableAsInt:

int isSubscribed;
-
-if(ts3client_getChannelVariableAsInt(scHandlerID, channelID, CHANNEL_FLAG_ARE_SUBSCRIBED, &isSubscribed)
-   != ERROR_ok) {
-    /* Handle error */
-}

The following event will be sent for each successfully subscribed channel: -

void onChannelSubscribeEvent(serverConnectionHandlerID,  
 channelID); 
uint64 serverConnectionHandlerID;
uint64 channelID;
 

-

Provided for convinience, to mark the end of mulitple calls to onChannelSubscribeEvent when subscribing to several channels, this event is called: -

void onChannelSubscribeFinishedEvent(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-

The following event will be sent for each successfully unsubscribed channel: -

void onChannelUnsubscribeEvent(serverConnectionHandlerID,  
 channelID); 
uint64 serverConnectionHandlerID;
uint64 channelID;
 

-

Similar like subscribing, this event is a convinience callback to mark the end of multiple calls to onChannelUnsubscribeEvent: -

void onChannelUnsubscribeFinishedEvent(serverConnectionHandlerID); 
uint64 serverConnectionHandlerID;
 

-

Once a channel has been subscribed or unsubscribed, the event onClientMoveSubscriptionEvent is sent for each client in the subscribed channel. The event is not to be confused with onClientMoveEvent, which is called for clients actively switching channels.

void onClientMoveSubscriptionEvent(serverConnectionHandlerID,  
 clientID,  
 oldChannelID,  
 newChannelID,  
 visibility); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64 oldChannelID;
uint64 newChannelID;
int visibility;
 
  • serverConnectionHandlerID

    The server connection handler ID for the server where the action occured.

  • clientID

    The client ID.

  • oldChannelID

    ID of the subscribed channel where the client left visibility.

  • newChannelID

    ID of the subscribed channel where the client entered visibility.

  • visibility

    Defined in the enum Visibility -

    enum Visibility {
    -    ENTER_VISIBILITY = 0,
    -    RETAIN_VISIBILITY,
    -    LEAVE_VISIBILITY
    -};

    -

    • ENTER_VISIBILITY

      Client entered visibility.

    • LEAVE_VISIBILITY

      Client left visibility.

    • RETAIN_VISIBILITY

      Does not occur with onClientMoveSubscriptionEvent.

diff --git a/pluginsdk/docs/client_html/ar01s24.html b/pluginsdk/docs/client_html/ar01s24.html deleted file mode 100644 index 45601f9..0000000 --- a/pluginsdk/docs/client_html/ar01s24.html +++ /dev/null @@ -1,13 +0,0 @@ -Muting clients locally

Muting clients locally

Individual clients can be locally muted. This information is handled client-side only and not visibile to other clients. It mainly serves as a sort of individual "ban" or "ignore" feature, where users can decide not to listen to certain clients anymore.

When a client becomes muted, he will no longer be heard by the muter. Also the TeamSpeak 3 server will stop sending voice packets.

The mute state is not visible to the muted client nor to other clients. It is only available to the muting client by checking the CLIENT_IS_MUTED client property.

To mute one or more clients: -

unsigned int ts3client_requestMuteClients(serverConnectionHandlerID,  
 clientIDArray,  
 returnCode); 
uint64 serverConnectionHandlerID;
const anyID* clientIDArray;
const char* returnCode;
 

-

To unmute one or more clients: -

unsigned int ts3client_requestUnmuteClients(serverConnectionHandlerID,  
 clientIDArray,  
 returnCode); 
uint64 serverConnectionHandlerID;
const anyID* clientIDArray;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the server connection handle on which the client should be locally (un)muted

  • clientIDArray

    NULL-terminated array of client IDs.

  • returnCode

    See return code documentation. Pass NULL if you do not need this feature.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.

Example to mute two clients:

anyID clientIDArray[3];  // List of two clients plus terminating zero
-clientIDArray[0] = 123;  // First client ID to mute
-clientIDArray[1] = 456;  // Second client ID to mute
-clientIDArray[2] = 0;    // Terminating zero
-
-if(ts3client_requestMuteClients(scHandlerID, clientIDArray) != ERROR_ok)  /* Mute clients */
-    printf("Error muting clients: %d\n", error);

To check if a client is currently muted, query the CLIENT_IS_MUTED client property:

int clientIsMuted;
-if(ts3client_getClientVariableAsInt(scHandlerID, clientID, CLIENT_IS_MUTED, &clientIsMuted) != ERROR_ok)
-    printf("Error querying client muted state\n);
diff --git a/pluginsdk/docs/client_html/ar01s25.html b/pluginsdk/docs/client_html/ar01s25.html deleted file mode 100644 index 5a960f6..0000000 --- a/pluginsdk/docs/client_html/ar01s25.html +++ /dev/null @@ -1,24 +0,0 @@ -Custom encryption

Custom encryption

As an optional feature, the TeamSpeak 3 SDK allows users to implement custom encryption and decryption for all network traffic. Custom encryption replaces the default AES encryption implemented by the TeamSpeak 3 SDK. A possible reason to apply own encryption might be to make ones TeamSpeak 3 client/server incompatible to other SDK implementations.

Custom encryption must be implemented the same way in both the client and server.

[Note]Note

If you do not want to use this feature, just don't implement the two encryption callbacks.

- To encrypt outgoing data, implement the callback: -

void onCustomPacketEncryptEvent(dataToSend,  
 sizeOfData); 
char** dataToSend;
unsigned int* sizeOfData;
 

- -

  • dataToSend

    Pointer to an array with the outgoing data to be encrypted.

    Apply your custom encryption to the data array. If the encrypted data is smaller than sizeOfData, write your encrypted data into the existing memory of dataToSend. If your encrypted data is larger, you need to allocate memory and redirect the pointer dataToSend. You need to take care of freeing your own allocated memory yourself. The memory allocated by the SDK, to which dataToSend is originally pointing to, must not be freed.

  • sizeOfData

    Pointer to an integer value containing the size of the data array.

-


-

- To decrypt incoming data, implement the callback: -

void onCustomPacketDecryptEvent(dataReceived,  
 dataReceivedSize); 
char** dataReceived;
unsigned int* dataReceivedSize;
 

- -

  • dataReceived

    Pointer to an array with the received data to be decrypted.

    Apply your custom decryption to the data array. If the decrypted data is smaller than dataReceivedSize, write your decrypted data into the existing memory of dataReceived. If your decrypted data is larger, you need to allocate memory and redirect the pointer dataReceived. You need to take care of freeing your own allocated memory yourself. The memory allocated by the SDK, to which dataReceived is originally pointing to, must not be freed.

  • dataReceivedSize

    Pointer to an integer value containing the size of the data array.

-

Example code implementing a very simple XOR custom encryption and decryption (also see the SDK examples):

void onCustomPacketEncryptEvent(char** dataToSend, unsigned int* sizeOfData) {
-    unsigned int i;
-    for(i = 0; i < *sizeOfData; i++) {
-        (*dataToSend)[i] ^= CUSTOM_CRYPT_KEY;
-    }
-}
-
-void onCustomPacketDecryptEvent(char** dataReceived, unsigned int* dataReceivedSize) {
-    unsigned int i;
-    for(i = 0; i < *dataReceivedSize; i++) {
-        (*dataReceived)[i] ^= CUSTOM_CRYPT_KEY;
-    }
-}
diff --git a/pluginsdk/docs/client_html/ar01s26.html b/pluginsdk/docs/client_html/ar01s26.html deleted file mode 100644 index 8db2ed5..0000000 --- a/pluginsdk/docs/client_html/ar01s26.html +++ /dev/null @@ -1,3 +0,0 @@ -Custom passwords

Custom passwords

The TeamSpeak SDK has the optional ability to do custom password handling. This makes it possible to allow people on the server (or channels) with passwords that are checked against outside datasources, like LDAP or other databases.

-To implement custom password, both server and client need to add custom callbacks, which will be spontaneously called whenever a password check is done in TeamSpeak. The SDK developer can implement own checks to validate the password instead of using the TeamSpeak built-in mechanism.


-

Both Server and Client Lib can implement the following callback to encrypt a user password. This function is called in the Client Lib when a channel password is set.

This can be used to hash the password in the same way it is hashed in the outside data store. Or just copy the password to send the clear text to the server.

void onClientPasswordEncrypt(serverID,  
 plaintext,  
 encryptedText,  
 encryptedTextByteSize); 
uint64 serverID;
const char* plaintext;
char* encryptedText;
int encryptedTextByteSize;
 
  • serverID

    ID of the server the password call occured

  • plaintext

    The plaintext password

  • encryptedText

    Fill with your custom encrypted password. Must be a 0-terminated string with a size not larger than encryptedTextByteSize.

  • encryptedTextByteSize

    Size of the buffer pointed to by encryptedText.

diff --git a/pluginsdk/docs/client_html/ar01s27.html b/pluginsdk/docs/client_html/ar01s27.html deleted file mode 100644 index 7b10c9a..0000000 --- a/pluginsdk/docs/client_html/ar01s27.html +++ /dev/null @@ -1,19 +0,0 @@ -Other events

Other events

When a client starts or stops talking, a talk status change event is sent by the server: -

void onTalkStatusChangeEvent(serverConnectionHandlerID,  
 status,  
 isReceivedWhisper,  
 clientID); 
uint64 serverConnectionHandlerID;
int status;
int isReceivedWhisper;
anyID clientID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the event occured.

  • status

    Possible return values are defined by the enum TalkStatus:

    enum TalkStatus {
    -    STATUS_NOT_TALKING = 0,
    -    STATUS_TALKING = 1,
    -    STATUS_TALKING_WHILE_DISABLED = 2,
    -};

    STATUS_TALKING and STATUS_NOT_TALKING are triggered everytime a client starts or stops talking. STATUS_TALKING_WHILE_DISABLED is triggered only if the microphone is muted. A client application might use this to implement a mechanism warning the user he is talking while not sending to the server or just ignore this value.

  • isReceivedWhisper

    1 if the talk event was caused by whispering, 0 if caused by normal talking.

  • clientID

    ID of the client who started or stopped talking.


-

If a client drops his connection, a timeout event is announced by the server: -

void onClientMoveTimeoutEvent(serverConnectionHandlerID,  
 clientID,  
 oldChannelID,  
 newChannelID,  
 visibility,  
 timeoutMessage); 
uint64 serverConnectionHandlerID;
anyID clientID;
uint64 oldChannelID;
uint64 newChannelID;
int visibility;
const char* timeoutMessage;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the event occured.

  • clientID

    ID of the moved client.

  • oldChannelID

    ID of the channel the leaving client was previously member of.

  • newChannelID

    0, as client is leaving.

  • visibility

    Always LEAVE_VISIBILITY.

  • timeoutMessage

    Optional message giving the reason for the timeout. UTF-8 encoded.


-

When the description of a channel was edited, the following event is called: -

void onChannelDescriptionUpdateEvent(serverConnectionHandlerID,  
 channelID); 
uint64 serverConnectionHandlerID;
uint64 channelID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the event occured.

  • shutdownMessage

    ID of the channel with the edited description.

The new description can be queried with ts3client_getChannelVariableAsString(channelID, CHANNEL_DESCRIPTION).


-

The following event tells the client that the specified channel has been modified. The GUI should fetch the channel data with ts3client_getChannelVariableAsInt and ts3client_getChannelVariableAsString and update the channel display. -

void onUpdateChannelEvent(serverConnectionHandlerID,  
 channelID); 
uint64 serverConnectionHandlerID;
uint64 channelID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the event occured.

  • channelID

    ID of the updated channel.


-

The following event is called when a channel password was modified. The GUI might remember previously entered channel passwords, so this callback announces the stored password might be invalid. -

void onChannelPasswordChangedEvent(serverConnectionHandlerID,  
 channelID); 
uint64 serverConnectionHandlerID;
uint64 channelID;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the event occured.

  • channelID

    ID of the channel with the changed password.

diff --git a/pluginsdk/docs/client_html/ar01s28.html b/pluginsdk/docs/client_html/ar01s28.html deleted file mode 100644 index 6c48071..0000000 --- a/pluginsdk/docs/client_html/ar01s28.html +++ /dev/null @@ -1,14 +0,0 @@ -Miscellaneous functions

Miscellaneous functions

Memory dynamically allocated in the Client Lib needs to be released with: -

unsigned int ts3client_freeMemory(pointer); 
void* pointer;
 

-

  • pointer

    Address of the variable to be released.

Example:

char* version;
-
-if(ts3client_getClientLibVersion(&version) == ERROR_ok) {
-    printf("Version: %s\n", version);
-    ts3client_freeMemory(version);
-}
[Important]Important

Memory must not be released if the function, which dynamically allocated the memory, returned an error. In that case, the result is undefined and not initialized, so freeing the memory might crash the application.


-

Instead of sending the sound through the network, it can be routed directly through the playback device, so the user will get immediate audible feedback when for example configuring some sound settings. -

unsigned int ts3client_setLocalTestMode(serverConnectionHandlerID,  
 status); 
uint64 serverConnectionHandlerID;
intstatus;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler for which the local test mode should be enabled or disabled.

  • status

    Pass 1 to enable local test mode, 0 to disable.

Returns ERROR_ok on success, otherwise an error code as defined in public_errors.h.


-

With the delayed temporary channel deletion feature, users can define after how many seconds a temporary channel will be deleted after the last client has left the channel. The delay is defined by setting the channel variable CHANNEL_DELETE_DELAY. This variable can be set and queried as described in channel information.

To query the time in seconds since the last client has left a temporary channel, call: -

unsigned int ts3client_getChannelEmptySecs(serverConnectionHandlerID,  
 channelID,  
 result); 
uint64 serverConnectionHandlerID;
uint64 channelID;
int* result;
 

-

  • serverConnectionHandlerID

    ID of the server connection handler on which the time should be queried.

  • channelID

    ID of the channel to query.

  • result

    Address of a variable that receives the time in seconds.

diff --git a/pluginsdk/docs/client_html/ar01s29.html b/pluginsdk/docs/client_html/ar01s29.html deleted file mode 100644 index 7f05441..0000000 --- a/pluginsdk/docs/client_html/ar01s29.html +++ /dev/null @@ -1,95 +0,0 @@ -Filetransfer

Filetransfer

The TeamSpeak SDK includes the ability to support filetransfer, like the regular TeamSpeak server and client offer. The Server can function as a file storage, which can be accessed by Clients who can up- and download files. Files are stored on the filesystem where the server is running.

In general, clients can initiate filetransfer actions like uploading or downloading a file, requesting file information (size, name, path etc.), list files in a directory and so on. The functions to call these actions are explained in detail below. In addition to the functions actively called, there are filetransfer related callbacks which are triggered when the server returned the requested information (e.g. list of files in a directory).

Each transfer is identified by a transferID, which is passed to most filetransfer functions. Transfer IDs are unique during the time of the transfer, but may be reused again some time after the previous transfer with the same ID has finished.

Files are organized on the server inside channels (identified by their channelID. The top-level directory in each channel is “/”. Subdirectories in each channel may exist and are defined with a path of the form “/dir1/dir2”. Subdirectories are optional and need to be created with ts3client_requestCreateDirectory, the channel root directory always exists by default.

Query information

The following functions allow to query information about a file transfer identified by its transferID.

Query the file name of the specified transfer: -

unsigned int ts3client_getTransferFileName(transferID,  
 result); 
anyID transferID;
char** result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Points to a C string containing the file name. Remember to call ts3client_freeMemory to release the string, which is dynamically allocated in the clientlib.


-

Query the file path of the specified transfer: -

unsigned int ts3client_getTransferFilePath(transferID,  
 result); 
anyID transferID;
char** result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Points to a C string containing the file path. Remember to call ts3client_freeMemory to release the string, which is dynamically allocated in the clientlib.


-

Query the remote path on the server of the specified transfer: -

unsigned int ts3client_getTransferFileRemotePath(transferID,  
 result); 
anyID transferID;
char** result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Points to a C string containing the remote path on the server. Remember to call ts3client_freeMemory to release the string, which is dynamically allocated in the clientlib.


-

Query the file size of the specified transfer: -

unsigned int ts3client_getTransferFileSize(transferID,  
 result); 
anyID transferID;
uint64* result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    File size of the transfer.


-

Query the currently transferred file size of the queried transfer: -

unsigned int ts3client_getTransferFileSizeDone(transferID,  
 result); 
anyID transferID;
uint64* result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Already transferred size of the transfer.


-

Query if the specified transfer is an upload or download: -

unsigned int ts3client_isTransferSender(transferID,  
 result); 
anyID transferID;
int* result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    1 == upload, 0 == download


-

Query the status of the specified transfer: -

unsigned int ts3client_getTransferStatus(transferID,  
 result); 
anyID transferID;
int* result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Current status of the file transfer, specified by the struct FileTransferState: -

    enum FileTransferState {
    -    FILETRANSFER_INITIALISING = 0,
    -    FILETRANSFER_ACTIVE,
    -    FILETRANSFER_FINISHED,
    -};

    -


-

Query the current speed of the specified transfer: -

unsigned int ts3client_getCurrentTransferSpeed(transferID,  
 result); 
anyID transferID;
float* result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Currently measured speed of the file transfer.


-

Query the average speed of the specified transfer: -

unsigned int ts3client_getAverageTransferSpeed(transferID,  
 result); 
anyID transferID;
float* result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Average speed of the file transfer.


-

Query the time the specified transfer has used: -

unsigned int ts3client_getTransferRunTime(transferID,  
 result); 
anyID transferID;
uint64* result;
 

-

  • transferID

    ID of the filetransfer we want to query.

  • result

    Time the transfer has used.


-

Initiate transfers

The following functions implement the core functionality of filetransfers. They initiate new up- and downloads, request file info, delete and rename files, create directories, list directories etc.

Request uploading a local file to the server: -

unsigned int ts3client_sendFile(serverConnectionHandlerID,  
 channelID,  
 channelPW,  
 file,  
 overwrite,  
 resume,  
 sourceDirectory,  
 result,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* channelPW;
const char* file;
int overwrite;
int resume;
const char* sourceDirectory;
anyID* result;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • channelID

    Target channel ID in which the file should be uploaded.

  • channelPW

    Optional channel password. Pass empty string if unused.

  • file

    Filename of the local file, which is to be uploaded.

  • overwrite

    1 == overwrite remote file if it exists, 0 = do not overwrite (operation will abort if remote file exists)

  • resume

    If we have a previously halted transfer: 1 = resume, 0 = restart transfer

  • sourceDirectory

    Local directory where the file to upload is located.

  • result

    Pointer to memory where the transferID will be stored, if the transfer has been started successfully (when this function returns ERROR_ok).

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.


-

Request downloading a file from the server: -

unsigned int ts3client_requestFile(serverConnectionHandlerID,  
 channelID,  
 channelPW,  
 file,  
 overwrite,  
 resume,  
 destinationDirectory,  
 result,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* channelPW;
const char* file;
int overwrite;
int resume;
const char* destinationDirectory;
anyID* result;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • channelID

    Remote channel ID from which the file should be downloaded.

  • channelPW

    Optional channel password. Pass empty string if unused.

  • file

    Filename of the remote file, which is to be downloaded.

  • overwrite

    1 == overwrite local file if it exists, 0 = do not overwrite (operation will abort if local file exists)

  • resume

    If we have a previously halted transfer: 1 = resume, 0 = restart transfer

  • destinationDirectory

    Local target directory name where the download file should be saved.

  • result

    Pointer to memory where the transferID will be stored, if the transfer has been started successfully (when this function returns ERROR_ok).

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.


-

Pause a transfer, specified by its transferID: -

unsigned int ts3client_haltTransfer(serverConnectionHandlerID,  
 transferID,  
 deleteUnfinishedFile,  
 returnCode); 
uint64 serverConnectionHandlerID;
anyID transferID;
int deleteUnfinishedFile;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • transferID

    ID of the transfer that should be halted.

  • deleteUnfinishedFile

    1 = delete the halted file, 0 = do not deleted halted file

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.


-

Query list of files in a directory. The answer from the server will trigger the onFileListEvent and onFileListFinishedEvent callbacks with the requested information. -

unsigned int ts3client_requestFileList(serverConnectionHandlerID,  
 channelID,  
 channelPW,  
 path,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* channelPW;
const char* path;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • channelID

    Remote channel ID, from which we want to query the file list.

  • channelPW

    Optional channel password. Pass empty string if unused.

  • path

    Path inside the channel, defining the subdirectory. Top level path is “/

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.


-

Query information of a specified file. The answer from the server will trigger the onFileInfoEvent callback with the requested information. -

unsigned int ts3client_requestFileInfo(serverConnectionHandlerID,  
 channelID,  
 channelPW,  
 file,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* channelPW;
const char* file;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • channelID

    Remote channel ID, from which we want to query the file info.

  • channelPW

    Optional channel password. Pass empty string if unused.

  • file

    File name we want to request info from, needs to include the full path within the channel, e.g. “/file” for a top-level file or “/dir1/dir2/file” for a file located in a subdirectory.

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.


-

Request deleting one or more remote files on the server: -

unsigned int ts3client_requestDeleteFile(serverConnectionHandlerID,  
 channelID,  
 channelPW,  
 file,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* channelPW;
const char** file;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • channelID

    Remote channel ID, in which we want to delete the files.

  • channelPW

    Optional channel password. Pass empty string if unused.

  • file

    List of files we request to delete. Array must be NULL-terminated. The file names need to include the full path within the channel, e.g. “/file” for a top-level file or “/dir1/dir2/file” for a file located in a subdirectory.

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.


-

Request creating a directory: -

unsigned int ts3client_requestCreateDirectory(serverConnectionHandlerID,  
 channelID,  
 channelPW,  
 directoryPath,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* channelPW;
const char* directoryPath;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • channelID

    Remote channel ID, in which we want to create the directory.

  • channelPW

    Optional channel password. Pass empty string if unused.

  • file

    Name of the directory to create. The directory name needs to include the full path within the channel, e.g. “/file” for a top-level file or “/dir1/dir2/file” for a file located in a subdirectory.

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.


-

Request renaming or moving a file. If the source and target channels and paths are the same, the file will simply be renamed. -

unsigned int ts3client_requestRenameFile(serverConnectionHandlerID,  
 fromChannelID,  
 fromChannelPW,  
 toChannelID,  
 toChannelPW,  
 oldFile,  
 newFile,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 fromChannelID;
const char* fromChannelPW;
uint64 toChannelID;
const char* toChannelPW;
const char* oldFile;
const char* newFile;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server the file transfer operation will be requested.

  • fromChannelID

    Source channel ID, in which we want to rename the file.

  • fromChannelPW

    Optional source channel password. Pass empty string if unused.

  • toChannelID

    Target channel ID, to which we want to move the file. If the file should not be moved to another channel, this parameter should be equal to fromChannelID.

  • toChannelPW

    Optional target channel password. Pass empty string if unused.

  • oldFile

    Old name of the file. The file name needs to include the full path within the channel, e.g. “/file” for a top-level file or “/dir1/dir2/file” for a file located in a subdirectory.

  • newFile

    Target name of the directory to create. The directory name need to include the full path within the channel, e.g. “/file” for a top-level file or “/dir1/dir2/file” for a file located in a subdirectory.

    To move files to another subdirectory in the same channel without renaming the file, fromChannelID has to be equal to toChannelID, keep the file name itself but just change the path.

  • returnCode

    String containing the return code if it has been set by the Client Lib function call which caused this error event.

    See return code documentation.

Speed limits

The TeamSpeak SDK offers the possibility to control and finetune transfer speed limits. These limits can be applied to the complete server, specific virtual servers or for each individual transfer. By default the transfer speed is unlimited. Every file transfer should at least have a minimum speed limit of 5kb/s.

Neither the TeamSpeak client nor server will store any of those values. When used, they'll have to be set at each client start to be considered permanent.

To set the upload speed limit for all virtual servers in bytes/s: -

unsigned int ts3client_setInstanceSpeedLimitUp(newLimit); 
uint64 newLimit;
 

-

To set the download speed limit for all virtual servers in bytes/s: -

unsigned int ts3client_setInstanceSpeedLimitDown(newLimit); 
uint64 newLimit;
 

-

To get the upload speed limit for all virtual servers in bytes/s: -

unsigned int ts3client_getInstanceSpeedLimitUp(limit); 
uint64* limit;
 

-

To get the download speed limit for all virtual servers in bytes/s: -

unsigned int ts3client_getInstanceSpeedLimitDown(limit); 
uint64* limit;
 

-

To set the upload speed limit for the specified virtual server in bytes/s: -

unsigned int ts3client_setServerConnectionHandlerSpeedLimitUp(serverConnectionHandlerID,  
 newLimit); 
uint64 serverConnectionHandlerID;
uint64 newLimit;
 

-

To set the download speed limit for the specified virtual server in bytes/s: -

unsigned int ts3client_setServerConnectionHandlerSpeedLimitDown(serverConnectionHandlerID,  
 newLimit); 
uint64 serverConnectionHandlerID;
uint64 newLimit;
 

-

To get the upload speed limit for the specified virtual server in bytes/s: -

unsigned int ts3client_getServerConnectionHandlerSpeedLimitUp(serverConnectionHandlerID,  
 limit); 
uint64 serverConnectionHandlerID;
uint64* limit;
 

-

To get the download speed limit for the specified virtual server in bytes/s: -

unsigned int ts3client_getServerConnectionHandlerSpeedLimitDown(serverConnectionHandlerID,  
 limit); 
uint64 serverConnectionHandlerID;
uint64* limit;
 

-

To set the up- or download speed limit for the specified file transfer in bytes/s. Use ts3client_isTransferSender to query if the transfer is an up- or download. -

unsigned int ts3client_setTransferSpeedLimit(transferID,  
 newLimit); 
anyID transferID;
uint64 newLimit;
 

-

To get the speed limit for the specified file transfer in bytes/s: -

unsigned int ts3client_getTransferSpeedLimit(transferID,  
 limit); 
anyID transferID;
uint64* limit;
 

-


-

Callbacks

This event is called when a file transfer, triggered by ts3client_sendFile or ts3client_requestFile has finished or aborted with an error. -

void onFileTransferStatusEvent(transferID,  
 status,  
 statusMessage,  
 remotefileSize,  
 serverConnectionHandlerID); 
anyID transferID;
unsigned int status;
const char* statusMessage;
uint64 remotefileSize;
uint64 serverConnectionHandlerID;
 

-

  • transferID

    ID of the transfer. This ID was returned by the call to ts3client_sendFile or ts3client_requestFile which triggered this event.

  • status

    Indicates how and why the transfer has finished:

    • ERROR_file_transfer_complete

      Transfer completed successfully.

    • ERROR_file_transfer_canceled

      Transfer was halted by a call to ts3client_haltTransfer.

    • ERROR_file_transfer_interrupted

      An error occured, transfer was stopped for various reasons (network error etc.)

    • ERROR_file_transfer_reset

      Transfer was reset. This can happen if the remote file has changed (another user uploaded another file under the same channel ID, path and file name).

  • statusMessage

    Status text message for a verbose display of the status parameter.

  • remotefileSize

    Remote size of the file on the server.

  • serverConnectionHandlerID

    ID of the virtual server on which the file list was requested.


-

Callback containing the reply by the server on ts3client_requestFileList. There event is called for every file in the specified path. After the last file, onFileListFinished will indicate the end of the list. -

void onFileListEvent(serverConnectionHandlerID,  
 channelID,  
 path,  
 name,  
 size,  
 datetime,  
 type,  
 incompletesize,  
 returnCode); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* path;
const char* name;
uint64 size;
uint64 datetime;
int type;
uint64 incompletesize;
const char* returnCode;
 

-

  • serverConnectionHandlerID

    ID of the virtual server on which the file list was requested.

  • channelID

    ID of the channel which file list was requested.

  • path

    Subdirectory inside the channel for which the file list was requested. “/” indicates the root directory is listed.

  • name

    File name.

  • size

    File size

  • datetime

    File date (Unix time in seconds)

  • type

    Indicates if this entry is a directory or a file. Type is specified as:

    enum {
    -    FileListType_Directory = 0,
    -    FileListType_File,
    -};
  • incompletesize

    If the file is currently still being transferred, this indicates the currently transferred file size.

  • returnCode

    String containing the return code if it has been set by ts3client_requestFileList which triggered this event.


-

Callback indicating the end of an incoming file list, see onFileList. -

void onFileListFinishedEvent(serverConnectionHandlerID,  
 channelID,  
 path); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* path;
 

-

  • serverConnectionHandlerID

    ID of the virtual server on which the file list was requested.

  • channelID

    If of the channel which files have been listed.

  • path

    Path within the channel which files have been listed.


-

Callback containing the reply by the server for ts3client_requestFileInfo: -

void onFileInfoEvent(serverConnectionHandlerID,  
 channelID,  
 name,  
 size,  
 datetime); 
uint64 serverConnectionHandlerID;
uint64 channelID;
const char* name;
uint64 size;
uint64 datetime;
 

-

  • serverConnectionHandlerID

    ID of the virtual server on which the file info was requested.

  • channelID

    If of the channel in which the file is located.

  • name

    File name including the path within the channel in which the file is located.

  • size

    File size

  • datetime

    File date (Unix time in seconds)

diff --git a/pluginsdk/docs/client_html/ar01s30.html b/pluginsdk/docs/client_html/ar01s30.html deleted file mode 100644 index fcc3559..0000000 --- a/pluginsdk/docs/client_html/ar01s30.html +++ /dev/null @@ -1,47 +0,0 @@ -FAQ

FAQ


-

How to implement Push-To-Talk?

Push-To-Talk should be implemented by toggling the client variable CLIENT_INPUT_DEACTIVATED using the function ts3client_setClientSelfVariableAsInt. The variable can be set to the following values (see the enum InputDeactivationStatus in public_definitions.h):

  • INPUT_ACTIVE

  • INPUT_DEACTIVATED

For Push-To-Talk toggle between INPUT_ACTIVE (talking) and INPUT_DEACTIVATED (not talking).

Example code:

unsigned int error;
-bool shouldTalk;
-
-shouldTalk = isPushToTalkButtonPressed();  // Your key detection implementation
-if((error = ts3client_setClientSelfVariableAsInt(scHandlerID, CLIENT_INPUT_DEACTIVATED,
-                                                 shouldTalk ? INPUT_ACTIVE : INPUT_DEACTIVATED))
-    != ERROR_ok) {
-    char* errorMsg;
-    if(ts3client_getErrorMessage(error, &errorMsg) != ERROR_ok) {
-        printf("Error toggling push-to-talk: %s\n", errorMsg);
-        ts3client_freeMemory(errorMsg);
-    }
-    return;
-}
-
-if(ts3client_flushClientSelfUpdates(scHandlerID, NULL) != ERROR_ok) {
-    char* errorMsg;
-    if(ts3client_getErrorMessage(error, &errorMsg) != ERROR_ok) {
-        printf("Error flushing after toggling push-to-talk: %s\n", errorMsg);
-        ts3client_freeMemory(errorMsg);
-    }
-}

It is not necessary to close and reopen the capture device to implement Push-To-Talk.

Basically it would be possible to toggle CLIENT_INPUT_MUTED as well, but the advantage of CLIENT_INPUT_DEACTIVATED is that the change is not propagated to the server and other connected clients, thus saving network traffic. CLIENT_INPUT_MUTED should instead be used for manually muting the microphone when using Voice Activity Detection instead of Push-To-Talk.

If you need to query the current muted state, use ts3client_getClientSelfVariableAsInt:

int hardwareStatus, deactivated, muted;
-
-if(ts3client_getClientSelfVariableAsInt(scHandlerID, CLIENT_INPUT_HARDWARE,
-                                        &hardwareStatus) != ERROR_ok) {
-    /* Handle error */
-}
-if(ts3client_getClientSelfVariableAsInt(scHandlerID, CLIENT_INPUT_DEACTIVATED,
-                                        &deactivated) != ERROR_ok) {
-    /* Handle error */
-}
-if(ts3client_getClientSelfVariableAsInt(scHandlerID, CLIENT_INPUT_MUTED,
-                                        &muted) != ERROR_ok) {
-    /* Handle error */
-}
-
-if(hardwareStatus == HARDWAREINPUT_DISABLED) {
-    /* No capture device available */
-}
-if(deactivated == INPUT_DEACTIVATED) {
-    /* Input was deactivated for Push-To-Talk (not propagated to server) */
-}
-if(muted == MUTEINPUT_MUTED) {
-    /* Input was muted (propagated to server) */
-}

When using Push-To-Talk, you should deactivate Voice Activity Detection in the preprocessor or keep the VAD level very low. To deactivate VAD, use:

ts3client_setPreProcessorConfigValue(serverConnectionHandlerID, "vad", "false");

How to adjust the volume?

Output volume

The global voice output volume can be adjusted by changing the “volume_modifierplayback option using the function ts3client_setPlaybackConfigValue. The value is in decibel, so 0 is no modification, negative values make the signal quieter and positive values louder.

Example to increase the output volume by 10 decibel: -

ts3client_setPlaybackConfigValue(scHandlerID, "volume_modifier", 10);

In addition to modifying the global output volue, the volume of individual clients can be changed with ts3client_setClientVolumeModifier.

Input volume

Automatic Gain Control (AGC) takes care of the input volume during preprocessing automatically. Instead of modifying the input volume directly, you modify the AGC preprocessor settings with setProProcessorConfigValue.

How to talk across channels?

Generally clients can only talk to other clients in the same channel. However, for specific scenarios this can be overruled using whisper lists.. This feature allows specific clients to temporarily talk to other clients or channels outside of their own channel. While whispering, talking to the own channel is disabled.

An example for a scenario where whisper may be useful would be a team consisting of a number of squads. Each squad is assigned to one channel, so squad members can only talk to other members of the same squad. In addition, there is a team leader and squad leaders, who want to communicate accross the squad channels. This can be implemented with whispering, so the team leader could broadcast to all squad leaders, or a squad leader could briefly report to the team leader temporarily sending his voice data to him instead of the squad leaders channel.

This mechanism is powerful and flexible allowing the SDK developer to handle more complex scenarios overruling the standard behaviour where clients can only talk to other clients within the same channel.

diff --git a/pluginsdk/docs/client_html/images/caution.png b/pluginsdk/docs/client_html/images/caution.png deleted file mode 100644 index f79d8393d897776a11ca8e87feb089ad74f772bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 887 zcmV--1Bm>IP)rfQOPo7r_eio!4f8L1m(9y|)4xJp_#6esfbnK!o4mvnn910bs zQ->B85ebT*2#TMe0TrwerB++5`M;?L^J1R*`tjsFF9ecv{^y)u?oDp)jRXMnh1w7L zV(lB~{{%WYIiX}SSr{VZ(Qa>V;q`h!L=Zw?Zf*|ww!DD)`};ved`Oanjg5`J1GKrh z2}zO|BnRd7dSMtw>47>sI~ihPVghcro3DexU}=GtmzTMCQ&SVt=`>=o7~2{e8jwsT zO9S-u^n~W-W-cBIh1low`Pe=_K3*E2nVA_b+Sb-)dR~r>j^J=OKtymj95_BcE-sL+ z>!_=%W1!X5Rf}e9Y>fTAy}iW+8XX;dx7gj?9qQ}rSr?1NiUV|dddkBgguubU0RZ6Q z;sT1IKv5K^stN!I27?Ub@p$n3{9Je-zu(VAhKGkuvvtm%12PN)?d|PspPij8EYSM; zI!}HzH8r@tzBavexx%}R$J{-|znzkgBR2R9#(-tE(#%s_D88m&?Vg%&o00i$?sq z=#R(aeE#_ONFI-;pxc~ODwW$@P&68)*49>&-vZRw*vRMEY?gFgFWMgLbuHU%P$rWx zt^A60_HBxgH_*QZ^b>e-al`u*WuE{5 N002ovPDHLkV1gvtn9l$J diff --git a/pluginsdk/docs/client_html/images/home.png b/pluginsdk/docs/client_html/images/home.png deleted file mode 100644 index 427c62814ceca61222848041302649635f637a20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 879 zcmV-#1CacQP)?E(Iv0Vd4M)0{lrt zK~z}7?U+wU6k!;~pLe#{HK-XeJ;l1x2EsPjNyI}zq!)?6=rRc25@Qd0h!zwHLTEwg z(xLJocw1y|tt1^J#e*gOL3D+n!$Nv+*_PdnOqTZP;w+=Bxqn-Nec*-p=AHSz-}ip= ze(%fxbyZO$6_WQzPLkXv`G(|$S^}M>Yo+#iu0#+UfLCUFXJ-eAL;~I2-R7y!B)0)5 z0PL1q;{X-`ycCgWrJ|yed}oGYYio7BYSY2I3XJ;ptmzRs0)ZE-$MKb9+ z$uH(Kg25mg8XAgP$ioe${s(VliH zjGyE$l1!)5?CP5@Y0S;67q z;Xi$2u#^^uwc39K;PUx=Xl`!C{{B9K!5}s^Hek2g;q&<_GWgWg6k@R$bX|wn>xIkZ zLQhYR>0Y-k*%j-)Lz0GJOfToB3X@Hx%BU{R4N5c)1WBj1v8t?BAHB<1QZ9* z4T(geqA-n(jTjmlGMkGck~!;{@sNzM z`uaxlMnPY$B-;Tz25<{NQ-u>L4qySm3lWLb{~`VN`VD5ftQuuk;J*L>002ovPDHLk FV1k^Qh2H=G diff --git a/pluginsdk/docs/client_html/images/important.png b/pluginsdk/docs/client_html/images/important.png deleted file mode 100644 index d35f5943b83a5f9851449a141f7929d238e10e9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 887 zcmV--1Bm>IP)?D=Zgb4a)!k0|ZG# zK~z}7?U+4C>rfQOPo7r_eio!4f8L1m(9y|)4xJp_#6esfbnK!o4mvnn910bs zQ->B85ebT*2#TMe0TrwerB++5`M;?L^J1R*`tjsFF9ecv{^y)u?oDp)jRXMnh1w7L zV(lB~{{%WYIiX}SSr{VZ(Qa>V;q`h!L=Zw?Zf*|ww!DD)`};ved`Oanjg5`J1GKrh z2}zO|BnRd7dSMtw>47>sI~ihPVghcro3DexU}=GtmzTMCQ&SVt=`>=o7~2{e8jwsT zO9S-u^n~W-W-cBIh1low`Pe=_K3*E2nVA_b+Sb-)dR~r>j^J=OKtymj95_BcE-sL+ z>!_=%W1!X5Rf}e9Y>fTAy}iW+8XX;dx7gj?9qQ}rSr?1NiUV|dddkBgguubU0RZ6Q z;sT1IKv5K^stN!I27?Ub@p$n3{9Je-zu(VAhKGkuvvtm%12PN)?d|PspPij8EYSM; zI!}HzH8r@tzBavexx%}R$J{-|znzkgBR2R9#(-tE(#%s_D88m&?Vg%&o00i$?sq z=#R(aeE#_ONFI-;pxc~ODwW$@P&68)*49>&-vZRw*vRMEY?gFgFWMgLbuHU%P$rWx zt^A60_HBxgH_*QZ^b>e-al`u*WuE{5 N002ovPDHLkV1k4gl|cXi diff --git a/pluginsdk/docs/client_html/images/logo.png b/pluginsdk/docs/client_html/images/logo.png deleted file mode 100644 index 075082239975b360ded97145b6bbd21ba0f3f5a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7194 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 diff --git a/pluginsdk/docs/client_html/images/next.png b/pluginsdk/docs/client_html/images/next.png deleted file mode 100644 index 7fa9992f06c145a56aa913fb3cb403f2f8ced40c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 681 zcmV;a0#^NrP)?E;^pVOy2+i0yarR zK~z}7?buJN5>Xfi@aK3VXwf3tv=&;ox?dtCY8m2xK^zlvp|p^ah6o7>0trK}-0E`g zcZdi#E!qUS8l=UzbYX2H^=adTz1K;{bk3q)IEy(mFu(WAnRDJ5;D78fNZuv+Zqe?M zJkW`WlbrK>9Owdl=IS`rf^tS@G#W7)jdD7jE~8F-M>%)4ZJPiXi^U}Bt*DHf zAyIF9L#+YXS4C{9N6e%_a(k0?1#}=aA$rZ6F6#E|-_P?q~%mr4S4Tm%F}d1vMHC7>3~- z&HfFmhj)gl)oK#+&~=UpP!hlq01Ssi*tWekiSc-h zNF?HVzFMuqG|lC%$4aS3n{KYxNPgSZ=31##0=~NnZNw zZ!5w}B(MCTktF;5{y9vsSd^IOzLl^NWEh6ruU>4lv+o0x$z&wvrC*rK5|m1%wySw| z4H^svjK|~h^QY^%e%=A?ECPh~mcsx50=!8? zK~z}7?O4xC0znl1Rs|slZ*SKu)~@YJhdvnC-FdTo^WHb}-V8%Tgg*om{uurV{RE3r z$Mf?uPESu!uh$_-((h+(GGTLb6WMGQPN!4ZkQA`BwM77QZ_#L!z60~sD(m%nu-okb zfMha>m6erWd#Ky(qFSv20GiDvJRXmF54Bn?c}9XDkRA{OLH?&Gii&m?EwdbrM#$&$ zczb)p-rgPpfq?$1*5aW|CNralcsx$!a+zLVUv=}4re%MBe?RliaUAyd_rbC(j*gD- z@bIwMeJB(P$h(I(>GX`e(w6JrZBr_%|J<7PHXwfMLobkFvkPKScQpe9Y3OeVUyxzSHUAHlLLIF7^m z`nsm@U0hrkS5v!OF7Q0BsT@%(`t&T&+U+*^{r(?A=61WO)9Dx!vX59>TLaJY@cDe- z+7$`~uq?ZnW02eJ2G8^GdcBG^(|Ubj=Q5AS1D@wU>CBK^rWRhW7tLl9mzS4d7zVLe z49R42zFhY5@}fCkscjaEg$9Fxwp_Nfw1ng1V?#Wb$z))&*%bSk@2+F+?(QIpBJ{Yi tVHgG*8ync(-Uh=k^AY;L{rD%O0`D?bJb4whJDC6g002ovPDHLkV1k&;ciaE~ diff --git a/pluginsdk/docs/client_html/images/prev.png b/pluginsdk/docs/client_html/images/prev.png deleted file mode 100644 index c1c82ea9722684fe8403552eba50036521e6aa9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 649 zcmV;40(Sk0P)?E+_rOAO-*c0v1U` zK~z}7?bxxa(?A>t@b9%wMR-2w<{uz!$LD{bPVNpNwxx6_g${v&g>LO6C|HCyq+*l` zD(KcXI66DEPK8J9AUJ91AP7yrF7NbAlcwj(%PsE*2Y2Ce_sK7iy9;m`7aSzBB#-$w zKA6UQ;&#kUVO}vJOkiHh$=B;O%jGhs)2V7YObe4C`CQKG`#!7HDgkgZnW&(vX6}o+mR; z)yy=T&3`f@%WO8IMoePRk(ehcrqybNVgPWlSWq**lf0($${qt~$%f-N7z_rHoyX%b z^7(x1gO*Aq6pKXwI0SGDz`K32^GJOZ$8jPvqgyP?Qip!959XnIN4wol45JMq*;jja zI-Nu@S|E~l)SlgLH*riHC=)Qr!t=b;QJIiyHvqgfh1voMA$$OqDOBjvA%yTrT4&9B5(NOG(I|2-&-0MW z6_7hSveiFOs+acTADQ(HcM%z+C`8 j0k}elkC#8HE-HQl`tlnt`16>H00000NkvXXu0mjfX~`7* diff --git a/pluginsdk/docs/client_html/images/up.png b/pluginsdk/docs/client_html/images/up.png deleted file mode 100644 index 9fd790394960e32045cc4eb3b6c0580f9b80c564..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 612 zcmV-q0-ODbP)?E*IM!5UKzG0r5#h zK~z}7?bxwv8etd)@aMe?G=G3YbqP8IN1=|LTDx@0AD|!?1QB8_f;fniLkodGp=1bc z+6GCSJ9OyKq0l8u*De)06$+*8;uTJxF1~VnJ;_DAUPyi5fjhrD@8{`#+zG7nzlCI( zveNGvNF@jt%2^9v#PFuh%nC`>|k(#UcR^06U$Ii8>%Dv0$|A zcH2ZfSve{!M%!w&Ow`krp)QNjHk(Zob+|NYQH-|HXmB!__)$j-qn5>J>-D;cdPdTU z1*5IiY9{IhNjnydwpy*4s8<)FqQYn^m5Pb#&qYOz(K?R9@p$Yz3!r{^9dkw}D|K2oU^GMP-6O;2=THbIHVDS%x7 zAE&4FU*t1@2O@H;FZj<8rUS-Y#8xzR=(x4$Cd0&s)I zEL^dyL2J;m344|O(uHg`i$bAr@h7z`B$G*99Rv8W%A0(P%V2LZTTeamSpeak 3 Client SDK Developer Manual

TeamSpeak 3 Client SDK Developer Manual

- Revision - 2019-06-11 17:55:55 - -


diff --git a/pluginsdk/docs/client_html/ix01.html b/pluginsdk/docs/client_html/ix01.html deleted file mode 100644 index 9ca049f..0000000 --- a/pluginsdk/docs/client_html/ix01.html +++ /dev/null @@ -1 +0,0 @@ -Index

Index

Symbols

3D sound, 3D Sound

A

AGC, Preprocessor options
Automatic Gain Control, Preprocessor options

B

bandwidth, Sound codecs

C

callback, The callback mechanism
calling convention, System requirements
capture device, Using playback and capture modes and devices
Channel order, Channel sorting
Channel voice data encryption, Channel voice data encryption
client ID, Connecting to a server
codec, Sound codecs

E

encoder, Encoder options
enums
ChannelProperties, Channel information
ClientProperties, Information related to own client, Information related to other clients
CodecEncryptionMode, Server information
ConnectStatus, Connecting to a server, Disconnecting from a server, Channel sorting
InputDeactivationStatus, How to implement Push-To-Talk?
LogLevel, Logging
LogType, Initializing, User-defined logging
TextMessageTargetMode, Receiving
VirtualServerProperties, Server information
Visibility, Joining a channel, Kicking clients, Channel subscriptions
error codes, Overview of header files
events
onChannelDescriptionUpdateEvent, Other events
onChannelMoveEvent, Moving a channel
onChannelPasswordChangedEvent, Other events
onChannelSubscribeEvent, Channel subscriptions
onChannelSubscribeFinishedEvent, Channel subscriptions
onChannelUnsubscribeEvent, Channel subscriptions
onChannelUnsubscribeFinishedEvent, Channel subscriptions
onClientKickFromChannelEvent, Kicking clients
onClientKickFromServerEvent, Kicking clients
onClientMoveEvent, Joining a channel
onClientMoveMovedEvent, Joining a channel
onClientMoveSubscriptionEvent, Channel subscriptions
onClientMoveTimeoutEvent, Other events
onClientPasswordEncrypt, Custom passwords
onConnectStatusChangeEvent, Connecting to a server, Disconnecting from a server
onCustom3dRolloffCalculationClientEvent, 3D Sound
onCustom3dRolloffCalculationWaveEvent, 3D Sound
onCustomPacketDecryptEvent, Custom encryption
onCustomPacketEncryptEvent, Custom encryption
onDelChannelEvent, Deleting a channel
onEditCapturedVoiceDataEvent, Accessing the voice buffer
onEditMixedPlaybackVoiceDataEvent, Accessing the voice buffer
onEditPlaybackVoiceDataEvent, Accessing the voice buffer
onEditPostProcessVoiceDataEvent, Accessing the voice buffer
onIgnoredWhisperEvent, Whisper lists
onNewChannelCreatedEvent, Creating a new channel
onNewChannelEvent, Connecting to a server
onPlaybackShutdownCompleteEvent, Closing devices
onServerEditedEvent, Server information
onServerErrorEvent, Return code, Error handling
onServerStopEvent, Disconnecting from a server
onServerUpdatedEvent, Server information
onTalkStatusChangeEvent, Other events
onTextMessageEvent, Receiving
onUpdateChannelEditedEvent, Channel information
onUpdateChannelEvent, Other events
onUpdateClientEvent, Information related to other clients
onUserLoggingMessageEvent, User-defined logging

F

FAQ, FAQ
Filetransfer, Filetransfer
functions
onFileInfoEvent, Callbacks
onFileListEvent, Callbacks
onFileListFinishedEvent, Callbacks
onFileTransferStatusEvent, Callbacks
ts3client_acquireCustomPlaybackData, Using custom devices
ts3client_activateCaptureDevice, Activating the capture device
ts3client_allowWhispersFrom, Whisper lists
ts3client_channelset3DAttributes, 3D Sound
ts3client_closeCaptureDevice, Closing devices
ts3client_closePlaybackDevice, Closing devices
ts3client_closeWaveFileHandle, Playing wave files
ts3client_createIdentity, Connecting to a server
ts3client_destroyClientLib, Shutting down
ts3client_destroyServerConnectionHandler, Managing server connection handlers
ts3client_flushChannelCreation, Creating a new channel
ts3client_flushChannelUpdates, Channel information
ts3client_flushClientSelfUpdates, Information related to own client
ts3client_freeMemory, Miscellaneous functions
ts3client_getAverageTransferSpeed, Query information
ts3client_getCaptureDeviceList, Querying available modes and devices
ts3client_getCaptureModeList, Querying available modes and devices
ts3client_getChannelClientList, Query available servers, channels and clients
ts3client_getChannelEmptySecs, Miscellaneous functions
ts3client_getChannelIDFromChannelNames, Channel information
ts3client_getChannelList, Query available servers, channels and clients
ts3client_getChannelOfClient, Query available servers, channels and clients
ts3client_getChannelVariableAsInt, Channel information
ts3client_getChannelVariableAsString, Channel information
ts3client_getChannelVariableAsUInt64, Channel information
ts3client_getClientID, Connecting to a server, Information related to own client
ts3client_getClientLibVersion, Querying the library version
ts3client_getClientLibVersionNumber, Querying the library version
ts3client_getClientList, Query available servers, channels and clients
ts3client_getClientSelfVariableAsInt, Information related to own client
ts3client_getClientSelfVariableAsString, Information related to own client
ts3client_getClientVariableAsInt, Information related to other clients
ts3client_getClientVariableAsString, Information related to other clients
ts3client_getClientVariableAsUInt64, Information related to other clients
ts3client_getConnectionStatus, Connecting to a server
ts3client_getCurrentCaptureDeviceName, Checking current modes and devices
ts3client_getCurrentCaptureMode, Checking current modes and devices
ts3client_getCurrentPlaybackDeviceName, Checking current modes and devices
ts3client_getCurrentPlayBackMode, Checking current modes and devices
ts3client_getCurrentTransferSpeed, Query information
ts3client_getDefaultCaptureDevice, Querying available modes and devices
ts3client_getDefaultCaptureMode, Querying available modes and devices
ts3client_getDefaultPlaybackDevice, Querying available modes and devices
ts3client_getDefaultPlayBackMode, Querying available modes and devices
ts3client_getEncodeConfigValue, Encoder options
ts3client_getErrorMessage, Error handling
ts3client_getInstanceSpeedLimitDown, Speed limits
ts3client_getInstanceSpeedLimitUp, Speed limits
ts3client_getParentChannelOfChannel, Query available servers, channels and clients
ts3client_getPlaybackConfigValueAsFloat, Playback options
ts3client_getPlaybackDeviceList, Querying available modes and devices
ts3client_getPlaybackModeList, Querying available modes and devices
ts3client_getPreProcessorConfigValue, Preprocessor options
ts3client_getPreProcessorInfoValueFloat, Preprocessor options
ts3client_getServerConnectionHandlerList, Query available servers, channels and clients
ts3client_getServerConnectionHandlerSpeedLimitDown, Speed limits
ts3client_getServerConnectionHandlerSpeedLimitUp, Speed limits
ts3client_getServerVariableAsInt, Server information
ts3client_getServerVariableAsString, Server information
ts3client_getServerVariableAsUInt64, Server information
ts3client_getTransferFileName, Query information
ts3client_getTransferFilePath, Query information
ts3client_getTransferFileRemotePath, Query information
ts3client_getTransferFileSize, Query information
ts3client_getTransferFileSizeDone, Query information
ts3client_getTransferRunTime, Query information
ts3client_getTransferSpeedLimit, Speed limits
ts3client_getTransferStatus, Query information
ts3client_haltTransfer, Initiate transfers
ts3client_initClientLib, Initializing
ts3client_initiateGracefulPlaybackShutdown, Closing devices
ts3client_isTransferSender, Query information
ts3client_logMessage, Logging
ts3client_openCaptureDevice, Initializing modes and devices
ts3client_openPlaybackDevice, Initializing modes and devices
ts3client_pauseWaveFileHandle, Playing wave files
ts3client_playWaveFile, Playing wave files
ts3client_playWaveFileHandle, Playing wave files
ts3client_processCustomCaptureData, Using custom devices
ts3client_registerCustomDevice, Using custom devices
ts3client_removeFromAllowedWhispersFrom, Whisper lists
ts3client_requestChannelDelete, Deleting a channel
ts3client_requestChannelDescription, Channel information
ts3client_requestChannelMove, Moving a channel
ts3client_requestChannelSubscribe, Channel subscriptions
ts3client_requestChannelSubscribeAll, Channel subscriptions
ts3client_requestChannelUnsubscribe, Channel subscriptions
ts3client_requestChannelUnsubscribeAll, Channel subscriptions
ts3client_requestClientKickFromChannel, Kicking clients
ts3client_requestClientKickFromServer, Kicking clients
ts3client_requestClientMove, Joining a channel
ts3client_requestClientSetWhisperList, Whisper lists
ts3client_requestClientVariables, Information related to other clients
ts3client_requestCreateDirectory, Initiate transfers
ts3client_requestDeleteFile, Initiate transfers
ts3client_requestFile, Initiate transfers
ts3client_requestFileInfo, Initiate transfers
ts3client_requestFileList, Initiate transfers
ts3client_requestMuteClients, Muting clients locally
ts3client_requestRenameFile, Initiate transfers
ts3client_requestSendChannelTextMsg, Sending
ts3client_requestSendPrivateTextMsg, Sending
ts3client_requestSendServerTextMsg, Sending
ts3client_requestServerVariables, Server information
ts3client_requestUnmuteClients, Muting clients locally
ts3client_sendFile, Initiate transfers
ts3client_set3DWaveAttributes, 3D Sound
ts3client_setChannelVariableAsInt, Channel information
ts3client_setChannelVariableAsString, Channel information
ts3client_setChannelVariableAsUInt64, Channel information
ts3client_setClientSelfVariableAsInt, Information related to own client
ts3client_setClientSelfVariableAsString, Information related to own client
ts3client_setClientVolumeModifier, Playback options
ts3client_setInstanceSpeedLimitDown, Speed limits
ts3client_setInstanceSpeedLimitUp, Speed limits
ts3client_setLocalTestMode, Miscellaneous functions
ts3client_setLogVerbosity, User-defined logging
ts3client_setPlaybackConfigValue, Playback options, How to adjust the volume?
ts3client_setPreProcessorConfigValue, Preprocessor options
ts3client_setServerConnectionHandlerSpeedLimitDown, Speed limits
ts3client_setServerConnectionHandlerSpeedLimitUp, Speed limits
ts3client_setTransferSpeedLimit, Speed limits
ts3client_spawnNewServerConnectionHandler, Managing server connection handlers
ts3client_startConnection, Connecting to a server
ts3client_startConnectionWithChannelID, Connecting to a server
ts3client_startVoiceRecording, Voice recording
ts3client_stopConnection, Disconnecting from a server
ts3client_stopVoiceRecording, Voice recording
ts3client_systemset3DListenerAttributes, 3D Sound
ts3client_systemset3DSettings, 3D Sound
ts3client_unregisterCustomDevice, Using custom devices

N

narrowband, Sound codecs

R

return code, Return code

S

sampling rates, Sound codecs
Semi-permanent channel, Channel information
server connection handler, Managing server connection handlers
structs
TS3_VECTOR, 3D Sound
system requirements, System requirements

U

ultra-wideband, Sound codecs

V

VAD, Preprocessor options
Voice Activity Detection, Preprocessor options
volume_factor_wave, Playback options
volume_modifier, Playback options, How to adjust the volume?

W

welcome message, Connecting to a server
wideband, Sound codecs
Windows, System requirements
diff --git a/pluginsdk/docs/client_html/ts3doc.css b/pluginsdk/docs/client_html/ts3doc.css deleted file mode 100644 index 3ff2b6f..0000000 --- a/pluginsdk/docs/client_html/ts3doc.css +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Stylesheet for TeamSpeak 3 SDK documentation - */ - -img { - border: 0; -} - -div.note { - border-left: solid #d5dee3 20px; - border-right: solid #d5dee3 20px; - margin-left: 5%; - margin-right: 10%; - padding: 5px; -} - -div.caution { - border-left: solid #d5dee3 20px; - border-right: solid #d5dee3 20px; - margin-left: 5%; - margin-right: 10%; - padding: 5px; -} - -div.important { - border-left: solid #d5dee3 20px; - border-right: solid #d5dee3 20px; - margin-left: 5%; - margin-right: 10%; - padding: 5px; -} - -.returnvalue { - font-family: monospace; - font-style: italic; - font-size: larger; -} - -p.legaltext { - font-size: 85%; -} - -p.larger { - font-size: 125%; -} - -#logo { - position: absolute; - left: 80%; -} diff --git a/pluginsdk/include/plugin_definitions.h b/pluginsdk/include/plugin_definitions.h deleted file mode 100644 index 104ac17..0000000 --- a/pluginsdk/include/plugin_definitions.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef PLUGIN_DEFINITIONS -#define PLUGIN_DEFINITIONS - -/* Return values for ts3plugin_offersConfigure */ -enum PluginConfigureOffer { - PLUGIN_OFFERS_NO_CONFIGURE = 0, /* Plugin does not implement ts3plugin_configure */ - PLUGIN_OFFERS_CONFIGURE_NEW_THREAD, /* Plugin does implement ts3plugin_configure and requests to run this function in an own thread */ - PLUGIN_OFFERS_CONFIGURE_QT_THREAD /* Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread */ -}; - -enum PluginMessageTarget { - PLUGIN_MESSAGE_TARGET_SERVER = 0, - PLUGIN_MESSAGE_TARGET_CHANNEL -}; - -enum PluginItemType { - PLUGIN_SERVER = 0, - PLUGIN_CHANNEL, - PLUGIN_CLIENT -}; - -enum PluginMenuType { - PLUGIN_MENU_TYPE_GLOBAL = 0, - PLUGIN_MENU_TYPE_CHANNEL, - PLUGIN_MENU_TYPE_CLIENT -}; - -#define PLUGIN_MENU_BUFSZ 128 - -struct PluginMenuItem { - enum PluginMenuType type; - int id; - char text[PLUGIN_MENU_BUFSZ]; - char icon[PLUGIN_MENU_BUFSZ]; -}; - -#define PLUGIN_HOTKEY_BUFSZ 128 - -struct PluginHotkey { - char keyword[PLUGIN_HOTKEY_BUFSZ]; - char description[PLUGIN_HOTKEY_BUFSZ]; -}; - -struct PluginBookmarkList; -struct PluginBookmarkItem { - char* name; - unsigned char isFolder; - unsigned char reserved[3]; - union{ - char* uuid; - struct PluginBookmarkList* folder; - }; -}; - -struct PluginBookmarkList{ - int itemcount; - struct PluginBookmarkItem items[1]; //should be 0 but compiler complains -}; - -enum PluginGuiProfile{ - PLUGIN_GUI_SOUND_CAPTURE = 0, - PLUGIN_GUI_SOUND_PLAYBACK, - PLUGIN_GUI_HOTKEY, - PLUGIN_GUI_SOUNDPACK, - PLUGIN_GUI_IDENTITY -}; - -enum PluginConnectTab{ - PLUGIN_CONNECT_TAB_NEW = 0, - PLUGIN_CONNECT_TAB_CURRENT, - PLUGIN_CONNECT_TAB_NEW_IF_CURRENT_CONNECTED -}; - -#endif diff --git a/pluginsdk/include/teamlog/logtypes.h b/pluginsdk/include/teamlog/logtypes.h deleted file mode 100755 index fc53910..0000000 --- a/pluginsdk/include/teamlog/logtypes.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TEAMLOG_LOGTYPES_H -#define TEAMLOG_LOGTYPES_H - -enum LogTypes { - LogType_NONE = 0x0000, - LogType_FILE = 0x0001, - LogType_CONSOLE = 0x0002, - LogType_USERLOGGING = 0x0004, - LogType_NO_NETLOGGING = 0x0008, - LogType_DATABASE = 0x0010, - LogType_SYSLOG = 0x0020, -}; - -enum LogLevel { - LogLevel_CRITICAL = 0, //these messages stop the program - LogLevel_ERROR, //everything that is really bad, but not so bad we need to shut down - LogLevel_WARNING, //everything that *might* be bad - LogLevel_DEBUG, //output that might help find a problem - LogLevel_INFO, //informational output, like "starting database version x.y.z" - LogLevel_DEVEL //developer only output (will not be displayed in release mode) -}; - -#endif //TEAMLOG_LOGTYPES_H diff --git a/pluginsdk/include/teamspeak/clientlib_publicdefinitions.h b/pluginsdk/include/teamspeak/clientlib_publicdefinitions.h deleted file mode 100644 index 35c0b84..0000000 --- a/pluginsdk/include/teamspeak/clientlib_publicdefinitions.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CLIENTLIB_PUBLICDEFINITIONS_H -#define CLIENTLIB_PUBLICDEFINITIONS_H - -enum Visibility { - ENTER_VISIBILITY = 0, - RETAIN_VISIBILITY, - LEAVE_VISIBILITY -}; - -enum ConnectStatus { - STATUS_DISCONNECTED = 0, //There is no activity to the server, this is the default value - STATUS_CONNECTING, //We are trying to connect, we haven't got a clientID yet, we haven't been accepted by the server - STATUS_CONNECTED, //The server has accepted us, we can talk and hear and we got a clientID, but we don't have the channels and clients yet, we can get server infos (welcome msg etc.) - STATUS_CONNECTION_ESTABLISHING,//we are CONNECTED and we are visible - STATUS_CONNECTION_ESTABLISHED, //we are CONNECTED and we have the client and channels available -}; - -enum LocalTestMode { - TEST_MODE_OFF = 0, - TEST_MODE_VOICE_LOCAL_ONLY, - TEST_MODE_VOICE_LOCAL_AND_REMOTE, - TEST_MODE_TALK_STATUS_CHANGES_ONLY -}; - -#endif //CLIENTLIB_PUBLICDEFINITIONS_H diff --git a/pluginsdk/include/teamspeak/public_definitions.h b/pluginsdk/include/teamspeak/public_definitions.h deleted file mode 100644 index f6b720e..0000000 --- a/pluginsdk/include/teamspeak/public_definitions.h +++ /dev/null @@ -1,392 +0,0 @@ -#ifndef PUBLIC_DEFINITIONS_H -#define PUBLIC_DEFINITIONS_H - -#include "teamlog/logtypes.h" - -//limited length, measured in characters -#define TS3_MAX_SIZE_CHANNEL_NAME 40 -#define TS3_MAX_SIZE_VIRTUALSERVER_NAME 64 -#define TS3_MAX_SIZE_CLIENT_NICKNAME 64 -#define TS3_MIN_SIZE_CLIENT_NICKNAME 3 -#define TS3_MAX_SIZE_REASON_MESSAGE 80 - -//limited length, measured in bytes (utf8 encoded) -#define TS3_MAX_SIZE_TEXTMESSAGE 8192 -#define TS3_MAX_SIZE_CHANNEL_TOPIC 255 -#define TS3_MAX_SIZE_CHANNEL_DESCRIPTION 8192 -#define TS3_MAX_SIZE_VIRTUALSERVER_WELCOMEMESSAGE 1024 -#define TS3_SIZE_MYTSID 44 - -//minimum amount of seconds before a clientID that was in use can be assigned to a new client -#define TS3_MIN_SECONDS_CLIENTID_REUSE 300 - -#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) - typedef unsigned __int16 anyID; - typedef unsigned __int64 uint64; - #ifdef BUILDING_DLL - #define EXPORTDLL __declspec(dllexport) - #else - #define EXPORTDLL - #endif -#else - #include - typedef uint16_t anyID; - typedef uint64_t uint64; - #ifdef BUILDING_DLL - #define EXPORTDLL __attribute__ ((visibility("default"))) - #else - #define EXPORTDLL - #endif -#endif - -enum TalkStatus { - STATUS_NOT_TALKING = 0, - STATUS_TALKING = 1, - STATUS_TALKING_WHILE_DISABLED = 2, -}; - -enum CodecType { - CODEC_SPEEX_NARROWBAND = 0, //mono, 16bit, 8kHz, bitrate dependent on the quality setting - CODEC_SPEEX_WIDEBAND, //mono, 16bit, 16kHz, bitrate dependent on the quality setting - CODEC_SPEEX_ULTRAWIDEBAND, //mono, 16bit, 32kHz, bitrate dependent on the quality setting - CODEC_CELT_MONO, //mono, 16bit, 48kHz, bitrate dependent on the quality setting - CODEC_OPUS_VOICE, //mono, 16bit, 48khz, bitrate dependent on the quality setting, optimized for voice - CODEC_OPUS_MUSIC, //stereo, 16bit, 48khz, bitrate dependent on the quality setting, optimized for music -}; - -enum CodecEncryptionMode { - CODEC_ENCRYPTION_PER_CHANNEL = 0, - CODEC_ENCRYPTION_FORCED_OFF, - CODEC_ENCRYPTION_FORCED_ON, -}; - -enum TextMessageTargetMode { - TextMessageTarget_CLIENT=1, - TextMessageTarget_CHANNEL, - TextMessageTarget_SERVER, - TextMessageTarget_MAX -}; - -enum MuteInputStatus { - MUTEINPUT_NONE = 0, - MUTEINPUT_MUTED, -}; - -enum MuteOutputStatus { - MUTEOUTPUT_NONE = 0, - MUTEOUTPUT_MUTED, -}; - -enum HardwareInputStatus { - HARDWAREINPUT_DISABLED = 0, - HARDWAREINPUT_ENABLED, -}; - -enum HardwareOutputStatus { - HARDWAREOUTPUT_DISABLED = 0, - HARDWAREOUTPUT_ENABLED, -}; - -enum InputDeactivationStatus { - INPUT_ACTIVE = 0, - INPUT_DEACTIVATED = 1, -}; - -enum ReasonIdentifier { - REASON_NONE = 0, //no reason data - REASON_MOVED = 1, //{SectionInvoker} - REASON_SUBSCRIPTION = 2, //no reason data - REASON_LOST_CONNECTION = 3, //reasonmsg=reason - REASON_KICK_CHANNEL = 4, //{SectionInvoker} reasonmsg=reason //{SectionInvoker} is only added server->client - REASON_KICK_SERVER = 5, //{SectionInvoker} reasonmsg=reason //{SectionInvoker} is only added server->client - REASON_KICK_SERVER_BAN = 6, //{SectionInvoker} reasonmsg=reason bantime=time //{SectionInvoker} is only added server->client - REASON_SERVERSTOP = 7, //reasonmsg=reason - REASON_CLIENTDISCONNECT = 8, //reasonmsg=reason - REASON_CHANNELUPDATE = 9, //no reason data - REASON_CHANNELEDIT = 10, //{SectionInvoker} - REASON_CLIENTDISCONNECT_SERVER_SHUTDOWN = 11, //reasonmsg=reason -}; - -enum ChannelProperties { - CHANNEL_NAME = 0, //Available for all channels that are "in view", always up-to-date - CHANNEL_TOPIC, //Available for all channels that are "in view", always up-to-date - CHANNEL_DESCRIPTION, //Must be requested (=> requestChannelDescription) - CHANNEL_PASSWORD, //not available client side - CHANNEL_CODEC, //Available for all channels that are "in view", always up-to-date - CHANNEL_CODEC_QUALITY, //Available for all channels that are "in view", always up-to-date - CHANNEL_MAXCLIENTS, //Available for all channels that are "in view", always up-to-date - CHANNEL_MAXFAMILYCLIENTS, //Available for all channels that are "in view", always up-to-date - CHANNEL_ORDER, //Available for all channels that are "in view", always up-to-date - CHANNEL_FLAG_PERMANENT, //Available for all channels that are "in view", always up-to-date - CHANNEL_FLAG_SEMI_PERMANENT, //Available for all channels that are "in view", always up-to-date - CHANNEL_FLAG_DEFAULT, //Available for all channels that are "in view", always up-to-date - CHANNEL_FLAG_PASSWORD, //Available for all channels that are "in view", always up-to-date - CHANNEL_CODEC_LATENCY_FACTOR, //Available for all channels that are "in view", always up-to-date - CHANNEL_CODEC_IS_UNENCRYPTED, //Available for all channels that are "in view", always up-to-date - CHANNEL_SECURITY_SALT, //Not available client side, not used in teamspeak, only SDK. Sets the options+salt for security hash. - CHANNEL_DELETE_DELAY, //How many seconds to wait before deleting this channel - CHANNEL_UNIQUE_IDENTIFIER, //Available for all channels that are "in view" - CHANNEL_ENDMARKER, -}; - -enum ClientProperties { - CLIENT_UNIQUE_IDENTIFIER = 0, //automatically up-to-date for any client "in view", can be used to identify this particular client installation - CLIENT_NICKNAME, //automatically up-to-date for any client "in view" - CLIENT_VERSION, //for other clients than ourself, this needs to be requested (=> requestClientVariables) - CLIENT_PLATFORM, //for other clients than ourself, this needs to be requested (=> requestClientVariables) - CLIENT_FLAG_TALKING, //automatically up-to-date for any client that can be heard (in room / whisper) - CLIENT_INPUT_MUTED, //automatically up-to-date for any client "in view", this clients microphone mute status - CLIENT_OUTPUT_MUTED, //automatically up-to-date for any client "in view", this clients headphones/speakers/mic combined mute status - CLIENT_OUTPUTONLY_MUTED, //automatically up-to-date for any client "in view", this clients headphones/speakers only mute status - CLIENT_INPUT_HARDWARE, //automatically up-to-date for any client "in view", this clients microphone hardware status (is the capture device opened?) - CLIENT_OUTPUT_HARDWARE, //automatically up-to-date for any client "in view", this clients headphone/speakers hardware status (is the playback device opened?) - CLIENT_INPUT_DEACTIVATED, //only usable for ourself, not propagated to the network - CLIENT_IDLE_TIME, //internal use - CLIENT_DEFAULT_CHANNEL, //only usable for ourself, the default channel we used to connect on our last connection attempt - CLIENT_DEFAULT_CHANNEL_PASSWORD, //internal use - CLIENT_SERVER_PASSWORD, //internal use - CLIENT_META_DATA, //automatically up-to-date for any client "in view", not used by TeamSpeak, free storage for sdk users - CLIENT_IS_MUTED, //only make sense on the client side locally, "1" if this client is currently muted by us, "0" if he is not - CLIENT_IS_RECORDING, //automatically up-to-date for any client "in view" - CLIENT_VOLUME_MODIFICATOR, //internal use - CLIENT_VERSION_SIGN, //sign - CLIENT_SECURITY_HASH, //SDK use, not used by teamspeak. Hash is provided by an outside source. A channel will use the security salt + other client data to calculate a hash, which must be the same as the one provided here. - CLIENT_ENCRYPTION_CIPHERS, //internal use - CLIENT_ENDMARKER, -}; - -enum VirtualServerProperties { - VIRTUALSERVER_UNIQUE_IDENTIFIER = 0, //available when connected, can be used to identify this particular server installation - VIRTUALSERVER_NAME, //available and always up-to-date when connected - VIRTUALSERVER_WELCOMEMESSAGE, //available when connected, (=> requestServerVariables) - VIRTUALSERVER_PLATFORM, //available when connected - VIRTUALSERVER_VERSION, //available when connected - VIRTUALSERVER_MAXCLIENTS, //only available on request (=> requestServerVariables), stores the maximum number of clients that may currently join the server - VIRTUALSERVER_PASSWORD, //not available to clients, the server password - VIRTUALSERVER_CLIENTS_ONLINE, //only available on request (=> requestServerVariables), - VIRTUALSERVER_CHANNELS_ONLINE, //only available on request (=> requestServerVariables), - VIRTUALSERVER_CREATED, //available when connected, stores the time when the server was created - VIRTUALSERVER_UPTIME, //only available on request (=> requestServerVariables), the time since the server was started - VIRTUALSERVER_CODEC_ENCRYPTION_MODE, //available and always up-to-date when connected - VIRTUALSERVER_ENCRYPTION_CIPHERS, //internal use - VIRTUALSERVER_ENDMARKER, -}; - -enum ConnectionProperties { - CONNECTION_PING = 0, //average latency for a round trip through and back this connection - CONNECTION_PING_DEVIATION, //standard deviation of the above average latency - CONNECTION_CONNECTED_TIME, //how long the connection exists already - CONNECTION_IDLE_TIME, //how long since the last action of this client - CONNECTION_CLIENT_IP, //IP of this client (as seen from the server side) - CONNECTION_CLIENT_PORT, //Port of this client (as seen from the server side) - CONNECTION_SERVER_IP, //IP of the server (seen from the client side) - only available on yourself, not for remote clients, not available server side - CONNECTION_SERVER_PORT, //Port of the server (seen from the client side) - only available on yourself, not for remote clients, not available server side - CONNECTION_PACKETS_SENT_SPEECH, //how many Speech packets were sent through this connection - CONNECTION_PACKETS_SENT_KEEPALIVE, - CONNECTION_PACKETS_SENT_CONTROL, - CONNECTION_PACKETS_SENT_TOTAL, //how many packets were sent totally (this is PACKETS_SENT_SPEECH + PACKETS_SENT_KEEPALIVE + PACKETS_SENT_CONTROL) - CONNECTION_BYTES_SENT_SPEECH, - CONNECTION_BYTES_SENT_KEEPALIVE, - CONNECTION_BYTES_SENT_CONTROL, - CONNECTION_BYTES_SENT_TOTAL, - CONNECTION_PACKETS_RECEIVED_SPEECH, - CONNECTION_PACKETS_RECEIVED_KEEPALIVE, - CONNECTION_PACKETS_RECEIVED_CONTROL, - CONNECTION_PACKETS_RECEIVED_TOTAL, - CONNECTION_BYTES_RECEIVED_SPEECH, - CONNECTION_BYTES_RECEIVED_KEEPALIVE, - CONNECTION_BYTES_RECEIVED_CONTROL, - CONNECTION_BYTES_RECEIVED_TOTAL, - CONNECTION_PACKETLOSS_SPEECH, - CONNECTION_PACKETLOSS_KEEPALIVE, - CONNECTION_PACKETLOSS_CONTROL, - CONNECTION_PACKETLOSS_TOTAL, //the probability with which a packet round trip failed because a packet was lost - CONNECTION_SERVER2CLIENT_PACKETLOSS_SPEECH, //the probability with which a speech packet failed from the server to the client - CONNECTION_SERVER2CLIENT_PACKETLOSS_KEEPALIVE, - CONNECTION_SERVER2CLIENT_PACKETLOSS_CONTROL, - CONNECTION_SERVER2CLIENT_PACKETLOSS_TOTAL, - CONNECTION_CLIENT2SERVER_PACKETLOSS_SPEECH, - CONNECTION_CLIENT2SERVER_PACKETLOSS_KEEPALIVE, - CONNECTION_CLIENT2SERVER_PACKETLOSS_CONTROL, - CONNECTION_CLIENT2SERVER_PACKETLOSS_TOTAL, - CONNECTION_BANDWIDTH_SENT_LAST_SECOND_SPEECH, //howmany bytes of speech packets we sent during the last second - CONNECTION_BANDWIDTH_SENT_LAST_SECOND_KEEPALIVE, - CONNECTION_BANDWIDTH_SENT_LAST_SECOND_CONTROL, - CONNECTION_BANDWIDTH_SENT_LAST_SECOND_TOTAL, - CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_SPEECH, //howmany bytes/s of speech packets we sent in average during the last minute - CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_KEEPALIVE, - CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_CONTROL, - CONNECTION_BANDWIDTH_SENT_LAST_MINUTE_TOTAL, - CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_SPEECH, - CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_KEEPALIVE, - CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_CONTROL, - CONNECTION_BANDWIDTH_RECEIVED_LAST_SECOND_TOTAL, - CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_SPEECH, - CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_KEEPALIVE, - CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_CONTROL, - CONNECTION_BANDWIDTH_RECEIVED_LAST_MINUTE_TOTAL, - CONNECTION_ENDMARKER, -}; - -typedef struct { - float x; /* X co-ordinate in 3D space. */ - float y; /* Y co-ordinate in 3D space. */ - float z; /* Z co-ordinate in 3D space. */ -} TS3_VECTOR; - -enum GroupWhisperType { - GROUPWHISPERTYPE_SERVERGROUP = 0, - GROUPWHISPERTYPE_CHANNELGROUP = 1, - GROUPWHISPERTYPE_CHANNELCOMMANDER = 2, - GROUPWHISPERTYPE_ALLCLIENTS = 3, - GROUPWHISPERTYPE_ENDMARKER, -}; - -enum GroupWhisperTargetMode { - GROUPWHISPERTARGETMODE_ALL = 0, - GROUPWHISPERTARGETMODE_CURRENTCHANNEL = 1, - GROUPWHISPERTARGETMODE_PARENTCHANNEL = 2, - GROUPWHISPERTARGETMODE_ALLPARENTCHANNELS = 3, - GROUPWHISPERTARGETMODE_CHANNELFAMILY = 4, - GROUPWHISPERTARGETMODE_ANCESTORCHANNELFAMILY = 5, - GROUPWHISPERTARGETMODE_SUBCHANNELS = 6, - GROUPWHISPERTARGETMODE_ENDMARKER, -}; - -enum MonoSoundDestination{ - MONO_SOUND_DESTINATION_ALL =0, /* Send mono sound to all available speakers */ - MONO_SOUND_DESTINATION_FRONT_CENTER =1, /* Send mono sound to front center speaker if available */ - MONO_SOUND_DESTINATION_FRONT_LEFT_AND_RIGHT =2 /* Send mono sound to front left/right speakers if available */ -}; - -enum SecuritySaltOptions { - SECURITY_SALT_CHECK_NICKNAME = 1, /* put nickname into security hash */ - SECURITY_SALT_CHECK_META_DATA = 2 /* put (game)meta data into security hash */ -}; - -/*this enum is used to disable client commands on the server*/ -enum ClientCommand{ - CLIENT_COMMAND_requestConnectionInfo = 0, - CLIENT_COMMAND_requestClientMove = 1, - CLIENT_COMMAND_requestXXMuteClients = 2, - CLIENT_COMMAND_requestClientKickFromXXX = 3, - CLIENT_COMMAND_flushChannelCreation = 4, - CLIENT_COMMAND_flushChannelUpdates = 5, - CLIENT_COMMAND_requestChannelMove = 6, - CLIENT_COMMAND_requestChannelDelete = 7, - CLIENT_COMMAND_requestChannelDescription = 8, - CLIENT_COMMAND_requestChannelXXSubscribeXXX = 9, - CLIENT_COMMAND_requestServerConnectionInfo = 10, - CLIENT_COMMAND_requestSendXXXTextMsg = 11, - CLIENT_COMMAND_filetransfers = 12, - CLIENT_COMMAND_ENDMARKER -}; - -/* Access Control List*/ -enum ACLType{ - ACL_NONE = 0, - ACL_WHITE_LIST = 1, - ACL_BLACK_LIST = 2 -}; - -/* file transfer actions*/ -enum FTAction{ - FT_INIT_SERVER = 0, - FT_INIT_CHANNEL = 1, - FT_UPLOAD = 2, - FT_DOWNLOAD = 3, - FT_DELETE = 4, - FT_CREATEDIR = 5, - FT_RENAME = 6, - FT_FILELIST = 7, - FT_FILEINFO = 8 -}; - -/* file transfer status */ -enum FileTransferState { - FILETRANSFER_INITIALISING = 0, - FILETRANSFER_ACTIVE, - FILETRANSFER_FINISHED, -}; - -/* file transfer types */ -enum { - FileListType_Directory = 0, - FileListType_File, -}; - -/* some structs to handle variables in callbacks */ -#define MAX_VARIABLES_EXPORT_COUNT 64 -struct VariablesExportItem{ - unsigned char itemIsValid; /* This item has valid values. ignore this item if 0 */ - unsigned char proposedIsSet; /* The value in proposed is set. if 0 ignore proposed */ - const char* current; /* current value (stored in memory) */ - const char* proposed; /* New value to change to (const, so no updates please) */ -}; - -struct VariablesExport{ - struct VariablesExportItem items[MAX_VARIABLES_EXPORT_COUNT]; -}; - -struct ClientMiniExport{ - anyID ID; - uint64 channel; - const char* ident; - const char* nickname; -}; - -struct TransformFilePathExport{ - uint64 channel; - const char* filename; - int action; - int transformedFileNameMaxSize; - int channelPathMaxSize; -}; - -struct TransformFilePathExportReturns{ - char* transformedFileName; - char* channelPath; - int logFileAction; -}; - -struct FileTransferCallbackExport{ - anyID clientID; - anyID transferID; - anyID remoteTransferID; - unsigned int status; - const char* statusMessage; - uint64 remotefileSize; - uint64 bytes; - int isSender; -}; - -/*define for file transfer bandwith limits*/ -#define BANDWIDTH_LIMIT_UNLIMITED 0xFFFFFFFFFFFFFFFFll - - -/*defines for speaker locations used by some sound callbacks*/ -#ifndef SPEAKER_FRONT_LEFT -#define SPEAKER_FRONT_LEFT 0x1 -#define SPEAKER_FRONT_RIGHT 0x2 -#define SPEAKER_FRONT_CENTER 0x4 -#define SPEAKER_LOW_FREQUENCY 0x8 -#define SPEAKER_BACK_LEFT 0x10 -#define SPEAKER_BACK_RIGHT 0x20 -#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 -#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 -#define SPEAKER_BACK_CENTER 0x100 -#define SPEAKER_SIDE_LEFT 0x200 -#define SPEAKER_SIDE_RIGHT 0x400 -#define SPEAKER_TOP_CENTER 0x800 -#define SPEAKER_TOP_FRONT_LEFT 0x1000 -#define SPEAKER_TOP_FRONT_CENTER 0x2000 -#define SPEAKER_TOP_FRONT_RIGHT 0x4000 -#define SPEAKER_TOP_BACK_LEFT 0x8000 -#define SPEAKER_TOP_BACK_CENTER 0x10000 -#define SPEAKER_TOP_BACK_RIGHT 0x20000 -#endif -#define SPEAKER_HEADPHONES_LEFT 0x10000000 -#define SPEAKER_HEADPHONES_RIGHT 0x20000000 -#define SPEAKER_MONO 0x40000000 - -#endif /*PUBLIC_DEFINITIONS_H*/ diff --git a/pluginsdk/include/teamspeak/public_errors.h b/pluginsdk/include/teamspeak/public_errors.h deleted file mode 100644 index 0659d3d..0000000 --- a/pluginsdk/include/teamspeak/public_errors.h +++ /dev/null @@ -1,194 +0,0 @@ -#ifndef PUBLIC_ERRORS_H -#define PUBLIC_ERRORS_H - -//The idea here is: the values are 2 bytes wide, the first byte identifies the group, the second the count within that group - -enum Ts3ErrorType { - //general - ERROR_ok = 0x0000, - ERROR_undefined = 0x0001, - ERROR_not_implemented = 0x0002, - ERROR_ok_no_update = 0x0003, - ERROR_dont_notify = 0x0004, - ERROR_lib_time_limit_reached = 0x0005, - ERROR_out_of_memory = 0x0006, - ERROR_canceled = 0x0007, - - //dunno - ERROR_command_not_found = 0x0100, - ERROR_unable_to_bind_network_port = 0x0101, - ERROR_no_network_port_available = 0x0102, - ERROR_port_already_in_use = 0x0103, - - //client - ERROR_client_invalid_id = 0x0200, - ERROR_client_nickname_inuse = 0x0201, - ERROR_client_protocol_limit_reached = 0x0203, - ERROR_client_invalid_type = 0x0204, - ERROR_client_already_subscribed = 0x0205, - ERROR_client_not_logged_in = 0x0206, - ERROR_client_could_not_validate_identity = 0x0207, - ERROR_client_version_outdated = 0x020a, - ERROR_client_is_flooding = 0x020c, - ERROR_client_hacked = 0x020d, - ERROR_client_cannot_verify_now = 0x020e, - ERROR_client_login_not_permitted = 0x020f, - ERROR_client_not_subscribed = 0x0210, - - //channel - ERROR_channel_invalid_id = 0x0300, - ERROR_channel_protocol_limit_reached = 0x0301, - ERROR_channel_already_in = 0x0302, - ERROR_channel_name_inuse = 0x0303, - ERROR_channel_not_empty = 0x0304, - ERROR_channel_can_not_delete_default = 0x0305, - ERROR_channel_default_require_permanent = 0x0306, - ERROR_channel_invalid_flags = 0x0307, - ERROR_channel_parent_not_permanent = 0x0308, - ERROR_channel_maxclients_reached = 0x0309, - ERROR_channel_maxfamily_reached = 0x030a, - ERROR_channel_invalid_order = 0x030b, - ERROR_channel_no_filetransfer_supported = 0x030c, - ERROR_channel_invalid_password = 0x030d, - ERROR_channel_invalid_security_hash = 0x030f, //note 0x030e is defined in public_rare_errors; - - //server - ERROR_server_invalid_id = 0x0400, - ERROR_server_running = 0x0401, - ERROR_server_is_shutting_down = 0x0402, - ERROR_server_maxclients_reached = 0x0403, - ERROR_server_invalid_password = 0x0404, - ERROR_server_is_virtual = 0x0407, - ERROR_server_is_not_running = 0x0409, - ERROR_server_is_booting = 0x040a, - ERROR_server_status_invalid = 0x040b, - ERROR_server_version_outdated = 0x040d, - ERROR_server_duplicate_running = 0x040e, - - //parameter - ERROR_parameter_quote = 0x0600, - ERROR_parameter_invalid_count = 0x0601, - ERROR_parameter_invalid = 0x0602, - ERROR_parameter_not_found = 0x0603, - ERROR_parameter_convert = 0x0604, - ERROR_parameter_invalid_size = 0x0605, - ERROR_parameter_missing = 0x0606, - ERROR_parameter_checksum = 0x0607, - - //unsorted, need further investigation - ERROR_vs_critical = 0x0700, - ERROR_connection_lost = 0x0701, - ERROR_not_connected = 0x0702, - ERROR_no_cached_connection_info = 0x0703, - ERROR_currently_not_possible = 0x0704, - ERROR_failed_connection_initialisation = 0x0705, - ERROR_could_not_resolve_hostname = 0x0706, - ERROR_invalid_server_connection_handler_id = 0x0707, - ERROR_could_not_initialise_input_manager = 0x0708, - ERROR_clientlibrary_not_initialised = 0x0709, - ERROR_serverlibrary_not_initialised = 0x070a, - ERROR_whisper_too_many_targets = 0x070b, - ERROR_whisper_no_targets = 0x070c, - ERROR_connection_ip_protocol_missing = 0x070d, - //reserved = 0x070e, - ERROR_illegal_server_license = 0x070f, - - //file transfer - ERROR_file_invalid_name = 0x0800, - ERROR_file_invalid_permissions = 0x0801, - ERROR_file_already_exists = 0x0802, - ERROR_file_not_found = 0x0803, - ERROR_file_io_error = 0x0804, - ERROR_file_invalid_transfer_id = 0x0805, - ERROR_file_invalid_path = 0x0806, - ERROR_file_no_files_available = 0x0807, - ERROR_file_overwrite_excludes_resume = 0x0808, - ERROR_file_invalid_size = 0x0809, - ERROR_file_already_in_use = 0x080a, - ERROR_file_could_not_open_connection = 0x080b, - ERROR_file_no_space_left_on_device = 0x080c, - ERROR_file_exceeds_file_system_maximum_size = 0x080d, - ERROR_file_transfer_connection_timeout = 0x080e, - ERROR_file_connection_lost = 0x080f, - ERROR_file_exceeds_supplied_size = 0x0810, - ERROR_file_transfer_complete = 0x0811, - ERROR_file_transfer_canceled = 0x0812, - ERROR_file_transfer_interrupted = 0x0813, - ERROR_file_transfer_server_quota_exceeded = 0x0814, - ERROR_file_transfer_client_quota_exceeded = 0x0815, - ERROR_file_transfer_reset = 0x0816, - ERROR_file_transfer_limit_reached = 0x0817, - - //sound - ERROR_sound_preprocessor_disabled = 0x0900, - ERROR_sound_internal_preprocessor = 0x0901, - ERROR_sound_internal_encoder = 0x0902, - ERROR_sound_internal_playback = 0x0903, - ERROR_sound_no_capture_device_available = 0x0904, - ERROR_sound_no_playback_device_available = 0x0905, - ERROR_sound_could_not_open_capture_device = 0x0906, - ERROR_sound_could_not_open_playback_device = 0x0907, - ERROR_sound_handler_has_device = 0x0908, - ERROR_sound_invalid_capture_device = 0x0909, - ERROR_sound_invalid_playback_device = 0x090a, - ERROR_sound_invalid_wave = 0x090b, - ERROR_sound_unsupported_wave = 0x090c, - ERROR_sound_open_wave = 0x090d, - ERROR_sound_internal_capture = 0x090e, - ERROR_sound_device_in_use = 0x090f, - ERROR_sound_device_already_registerred = 0x0910, - ERROR_sound_unknown_device = 0x0911, - ERROR_sound_unsupported_frequency = 0x0912, - ERROR_sound_invalid_channel_count = 0x0913, - ERROR_sound_read_wave = 0x0914, - ERROR_sound_need_more_data = 0x0915, //for internal purposes only - ERROR_sound_device_busy = 0x0916, //for internal purposes only - ERROR_sound_no_data = 0x0917, - ERROR_sound_channel_mask_mismatch = 0x0918, - - - //permissions - ERROR_permissions_client_insufficient = 0x0a08, - ERROR_permissions = 0x0a0c, - - //accounting - ERROR_accounting_virtualserver_limit_reached = 0x0b00, - ERROR_accounting_slot_limit_reached = 0x0b01, - ERROR_accounting_license_file_not_found = 0x0b02, - ERROR_accounting_license_date_not_ok = 0x0b03, - ERROR_accounting_unable_to_connect_to_server = 0x0b04, - ERROR_accounting_unknown_error = 0x0b05, - ERROR_accounting_server_error = 0x0b06, - ERROR_accounting_instance_limit_reached = 0x0b07, - ERROR_accounting_instance_check_error = 0x0b08, - ERROR_accounting_license_file_invalid = 0x0b09, - ERROR_accounting_running_elsewhere = 0x0b0a, - ERROR_accounting_instance_duplicated = 0x0b0b, - ERROR_accounting_already_started = 0x0b0c, - ERROR_accounting_not_started = 0x0b0d, - ERROR_accounting_to_many_starts = 0x0b0e, - - //provisioning server - ERROR_provisioning_invalid_password = 0x1100, - ERROR_provisioning_invalid_request = 0x1101, - ERROR_provisioning_no_slots_available = 0x1102, - ERROR_provisioning_pool_missing = 0x1103, - ERROR_provisioning_pool_unknown = 0x1104, - ERROR_provisioning_unknown_ip_location = 0x1105, - ERROR_provisioning_internal_tries_exceeded = 0x1106, - ERROR_provisioning_too_many_slots_requested = 0x1107, - ERROR_provisioning_too_many_reserved = 0x1108, - ERROR_provisioning_could_not_connect = 0x1109, - ERROR_provisioning_auth_server_not_connected = 0x1110, - ERROR_provisioning_auth_data_too_large = 0x1111, - ERROR_provisioning_already_initialized = 0x1112, - ERROR_provisioning_not_initialized = 0x1113, - ERROR_provisioning_connecting = 0x1114, - ERROR_provisioning_already_connected = 0x1115, - ERROR_provisioning_not_connected = 0x1116, - ERROR_provisioning_io_error = 0x1117, - ERROR_provisioning_invalid_timeout = 0x1118, - ERROR_provisioning_ts3server_not_found = 0x1119, - ERROR_provisioning_no_permission = 0x111A, -}; -#endif diff --git a/pluginsdk/include/teamspeak/public_errors_rare.h b/pluginsdk/include/teamspeak/public_errors_rare.h deleted file mode 100644 index 8a54792..0000000 --- a/pluginsdk/include/teamspeak/public_errors_rare.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef PUBLIC_ERRORS__RARE_H -#define PUBLIC_ERRORS__RARE_H - -//The idea here is: the values are 2 bytes wide, the first byte identifies the group, the second the count within that group - -enum Ts3RareErrorType { - //client - ERROR_client_invalid_password = 0x0208, - ERROR_client_too_many_clones_connected = 0x0209, - ERROR_client_is_online = 0x020b, - - //channel - ERROR_channel_is_private_channel = 0x030e, - //note 0x030f is defined in public_errors; - - //database - ERROR_database = 0x0500, - ERROR_database_empty_result = 0x0501, - ERROR_database_duplicate_entry = 0x0502, - ERROR_database_no_modifications = 0x0503, - ERROR_database_constraint = 0x0504, - ERROR_database_reinvoke = 0x0505, - - //permissions - ERROR_permission_invalid_group_id = 0x0a00, - ERROR_permission_duplicate_entry = 0x0a01, - ERROR_permission_invalid_perm_id = 0x0a02, - ERROR_permission_empty_result = 0x0a03, - ERROR_permission_default_group_forbidden = 0x0a04, - ERROR_permission_invalid_size = 0x0a05, - ERROR_permission_invalid_value = 0x0a06, - ERROR_permissions_group_not_empty = 0x0a07, - ERROR_permissions_insufficient_group_power = 0x0a09, - ERROR_permissions_insufficient_permission_power = 0x0a0a, - ERROR_permission_template_group_is_used = 0x0a0b, - //0x0a0c is in public_errors.h - ERROR_permission_used_by_integration = 0x0a0d, - - //server - ERROR_server_deployment_active = 0x0405, - ERROR_server_unable_to_stop_own_server = 0x0406, - ERROR_server_wrong_machineid = 0x0408, - ERROR_server_modal_quit = 0x040c, - ERROR_server_time_difference_too_large = 0x040f, - ERROR_server_blacklisted = 0x0410, - ERROR_server_shutdown = 0x0411, - - //messages - ERROR_message_invalid_id = 0x0c00, - - //ban - ERROR_ban_invalid_id = 0x0d00, - ERROR_connect_failed_banned = 0x0d01, - ERROR_rename_failed_banned = 0x0d02, - ERROR_ban_flooding = 0x0d03, - - //tts - ERROR_tts_unable_to_initialize = 0x0e00, - - //privilege key - ERROR_privilege_key_invalid = 0x0f00, - - //voip - ERROR_voip_pjsua = 0x1000, - ERROR_voip_already_initialized = 0x1001, - ERROR_voip_too_many_accounts = 0x1002, - ERROR_voip_invalid_account = 0x1003, - ERROR_voip_internal_error = 0x1004, - ERROR_voip_invalid_connectionId = 0x1005, - ERROR_voip_cannot_answer_initiated_call = 0x1006, - ERROR_voip_not_initialized = 0x1007, - - //ed25519 - ERROR_ed25519_rng_fail = 0x1300, - ERROR_ed25519_signature_invalid = 0x1301, - ERROR_ed25519_invalid_key = 0x1302, - ERROR_ed25519_unable_to_create_valid_key = 0x1303, - ERROR_ed25519_out_of_memory = 0x1304, - ERROR_ed25519_exists = 0x1305, - ERROR_ed25519_read_beyond_eof = 0x1306, - ERROR_ed25519_write_beyond_eof = 0x1307, - ERROR_ed25519_version = 0x1308, - ERROR_ed25519_invalid = 0x1309, - ERROR_ed25519_invalid_date = 0x130A, - ERROR_ed25519_unauthorized = 0x130B, - ERROR_ed25519_invalid_type = 0x130C, - ERROR_ed25519_address_nomatch = 0x130D, - ERROR_ed25519_not_valid_yet = 0x130E, - ERROR_ed25519_expired = 0x130F, - ERROR_ed25519_index_out_of_range = 0x1310, - ERROR_ed25519_invalid_size = 0x1311, - - //mytsid - client - ERROR_invalid_mytsid_data = 0x1200, - ERROR_invalid_integration = 0x1201, -}; - -#endif diff --git a/pluginsdk/include/teamspeak/public_rare_definitions.h b/pluginsdk/include/teamspeak/public_rare_definitions.h deleted file mode 100644 index c4e4cdc..0000000 --- a/pluginsdk/include/teamspeak/public_rare_definitions.h +++ /dev/null @@ -1,361 +0,0 @@ -#ifndef PUBLIC_RARE_DEFINITIONS_H -#define PUBLIC_RARE_DEFINITIONS_H - -#include "public_definitions.h" - -//limited length, measured in characters -#define TS3_MAX_SIZE_CLIENT_NICKNAME_NONSDK 30 -#define TS3_MIN_SIZE_CLIENT_NICKNAME_NONSDK 3 -#define TS3_MAX_SIZE_AWAY_MESSAGE 80 -#define TS3_MAX_SIZE_GROUP_NAME 30 -#define TS3_MAX_SIZE_TALK_REQUEST_MESSAGE 50 -#define TS3_MAX_SIZE_COMPLAIN_MESSAGE 200 -#define TS3_MAX_SIZE_CLIENT_DESCRIPTION 200 -#define TS3_MAX_SIZE_HOST_MESSAGE 200 -#define TS3_MAX_SIZE_HOSTBUTTON_TOOLTIP 50 -#define TS3_MAX_SIZE_POKE_MESSAGE 100 -#define TS3_MAX_SIZE_OFFLINE_MESSAGE 4096 -#define TS3_MAX_SIZE_OFFLINE_MESSAGE_SUBJECT 200 - -//limited length, measured in bytes (utf8 encoded) -#define TS3_MAX_SIZE_PLUGIN_COMMAND 1024*8 -#define TS3_MAX_SIZE_VIRTUALSERVER_HOSTBANNER_GFX_URL 2000 - - -enum GroupShowNameTreeMode { - GroupShowNameTreeMode_NONE= 0, //dont group show name - GroupShowNameTreeMode_BEFORE, //show group name before client name - GroupShowNameTreeMode_BEHIND //show group name behind client name -}; - -enum PluginTargetMode { - PluginCommandTarget_CURRENT_CHANNEL=0, //send plugincmd to all clients in current channel - PluginCommandTarget_SERVER, //send plugincmd to all clients on server - PluginCommandTarget_CLIENT, //send plugincmd to all given client ids - PluginCommandTarget_CURRENT_CHANNEL_SUBSCRIBED_CLIENTS, //send plugincmd to all subscribed clients in current channel - PluginCommandTarget_MAX -}; - -enum { - SERVER_BINDING_VIRTUALSERVER=0, - SERVER_BINDING_SERVERQUERY =1, - SERVER_BINDING_FILETRANSFER =2, -}; - -enum HostMessageMode { - HostMessageMode_NONE=0, //dont display anything - HostMessageMode_LOG, //display message inside log - HostMessageMode_MODAL, //display message inside a modal dialog - HostMessageMode_MODALQUIT //display message inside a modal dialog and quit/close server/connection -}; - -enum HostBannerMode { - HostBannerMode_NO_ADJUST=0, //Do not adjust - HostBannerMode_ADJUST_IGNORE_ASPECT, //Adjust but ignore aspect ratio - HostBannerMode_ADJUST_KEEP_ASPECT, //Adjust and keep aspect ratio -}; - -enum ClientType { - ClientType_NORMAL = 0, - ClientType_SERVERQUERY, -}; - -enum AwayStatus { - AWAY_NONE = 0, - AWAY_ZZZ, -}; - -enum CommandLinePropertiesRare { -#ifdef SERVER - COMMANDLINE_CREATE_DEFAULT_VIRTUALSERVER= 0, //create default virtualserver - COMMANDLINE_MACHINE_ID, //machine id (starts only virtualserver with given machineID - COMMANDLINE_DEFAULT_VOICE_PORT, - COMMANDLINE_VOICE_IP, - COMMANDLINE_THREADS_VOICE_UDP, - COMMANDLINE_LICENSEPATH, -#ifndef SDK - COMMANDLINE_FILETRANSFER_PORT, - COMMANDLINE_FILETRANSFER_IP, - COMMANDLINE_QUERY_PORT, - COMMANDLINE_QUERY_IP, - COMMANDLINE_QUERY_IP_WHITELIST, - COMMANDLINE_QUERY_IP_BLACKLIST, - COMMANDLINE_CLEAR_DATABASE, - COMMANDLINE_SERVERADMIN_PASSWORD, - COMMANDLINE_DBPLUGIN, - COMMANDLINE_DBPLUGINPARAMETER, - COMMANDLINE_DBSQLPATH, - COMMANDLINE_DBSQLCREATEPATH, - COMMANDLINE_DBCONNECTIONS, - COMMANDLINE_LOGPATH, - COMMANDLINE_CREATEINIFILE, - COMMANDLINE_INIFILE, - COMMANDLINE_LOGQUERYCOMMANDS, - COMMANDLINE_DBCLIENTKEEPDAYS, - COMMANDLINE_NO_PERMISSION_UPDATE, - COMMANDLINE_OPEN_WIN_CONSOLE, - COMMANDLINE_NO_PASSWORD_DIALOG, - COMMANDLINE_LOGAPPEND, - COMMANDLINE_QUERY_SKIPBRUTEFORCECHECK, - COMMANDLINE_QUERY_BUFFER_MB, - COMMANDLINE_HTTP_PROXY, - COMMANDLINE_LICENSE_ACCEPTED, - COMMANDLINE_SERVERQUERYDOCS_PATH, - COMMANDLINE_QUERY_SSH_IP, - COMMANDLINE_QUERY_SSH_PORT, - COMMANDLINE_QUERY_PROTOCOLS, - COMMANDLINE_QUERY_SSH_RSA_HOST_KEY, - COMMANDLINE_QUERY_TIMEOUT, - COMMANDLINE_VERSION, - COMMANDLINE_CRASHDUMPSPATH, - COMMANDLINE_DAEMON, - COMMANDLINE_PID_FILE, - COMMANDLINE_HINTS_ENABLED, -#endif -#else - COMMANDLINE_NOTHING=0, -#endif - COMMANDLINE_ENDMARKER_RARE, -}; - -enum ServerInstancePropertiesRare { - SERVERINSTANCE_DATABASE_VERSION= 0, - SERVERINSTANCE_FILETRANSFER_PORT, - SERVERINSTANCE_SERVER_ENTROPY, - SERVERINSTANCE_MONTHLY_TIMESTAMP, - SERVERINSTANCE_MAX_DOWNLOAD_TOTAL_BANDWIDTH, - SERVERINSTANCE_MAX_UPLOAD_TOTAL_BANDWIDTH, - SERVERINSTANCE_GUEST_SERVERQUERY_GROUP, - SERVERINSTANCE_SERVERQUERY_FLOOD_COMMANDS, //how many commands we can issue while in the SERVERINSTANCE_SERVERQUERY_FLOOD_TIME window - SERVERINSTANCE_SERVERQUERY_FLOOD_TIME, //time window in seconds for max command execution check - SERVERINSTANCE_SERVERQUERY_BAN_TIME, //how many seconds someone get banned if he floods - SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP, - SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP, - SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP, - SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP, - SERVERINSTANCE_PERMISSIONS_VERSION, - SERVERINSTANCE_PENDING_CONNECTIONS_PER_IP, - SERVERINSTANCE_SERVERQUERY_MAX_CONNECTIONS_PER_IP, - SERVERINSTANCE_ENDMARKER_RARE, -}; - -enum VirtualServerPropertiesRare { - VIRTUALSERVER_DUMMY_1 = VIRTUALSERVER_ENDMARKER, - VIRTUALSERVER_DUMMY_2, - VIRTUALSERVER_DUMMY_3, - VIRTUALSERVER_DUMMY_4, - VIRTUALSERVER_DUMMY_5, - VIRTUALSERVER_DUMMY_6, - VIRTUALSERVER_DUMMY_7, - VIRTUALSERVER_DUMMY_8, - VIRTUALSERVER_KEYPAIR, //internal use - VIRTUALSERVER_HOSTMESSAGE, //available when connected, not updated while connected - VIRTUALSERVER_HOSTMESSAGE_MODE, //available when connected, not updated while connected - VIRTUALSERVER_FILEBASE, //not available to clients, stores the folder used for file transfers - VIRTUALSERVER_DEFAULT_SERVER_GROUP, //the client permissions server group that a new client gets assigned - VIRTUALSERVER_DEFAULT_CHANNEL_GROUP, //the channel permissions group that a new client gets assigned when joining a channel - VIRTUALSERVER_FLAG_PASSWORD, //only available on request (=> requestServerVariables) - VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP, //the channel permissions group that a client gets assigned when creating a channel - VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH, //only available on request (=> requestServerVariables) - VIRTUALSERVER_HOSTBANNER_URL, //available when connected, always up-to-date - VIRTUALSERVER_HOSTBANNER_GFX_URL, //available when connected, always up-to-date - VIRTUALSERVER_HOSTBANNER_GFX_INTERVAL, //available when connected, always up-to-date - VIRTUALSERVER_COMPLAIN_AUTOBAN_COUNT, //only available on request (=> requestServerVariables) - VIRTUALSERVER_COMPLAIN_AUTOBAN_TIME, //only available on request (=> requestServerVariables) - VIRTUALSERVER_COMPLAIN_REMOVE_TIME, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MIN_CLIENTS_IN_CHANNEL_BEFORE_FORCED_SILENCE,//only available on request (=> requestServerVariables) - VIRTUALSERVER_PRIORITY_SPEAKER_DIMM_MODIFICATOR, //available when connected, always up-to-date - VIRTUALSERVER_ID, //available when connected - VIRTUALSERVER_ANTIFLOOD_POINTS_TICK_REDUCE, //only available on request (=> requestServerVariables) - VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_COMMAND_BLOCK, //only available on request (=> requestServerVariables) - VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_IP_BLOCK, //only available on request (=> requestServerVariables) - VIRTUALSERVER_CLIENT_CONNECTIONS, //only available on request (=> requestServerVariables) - VIRTUALSERVER_QUERY_CLIENT_CONNECTIONS, //only available on request (=> requestServerVariables) - VIRTUALSERVER_HOSTBUTTON_TOOLTIP, //available when connected, always up-to-date - VIRTUALSERVER_HOSTBUTTON_URL, //available when connected, always up-to-date - VIRTUALSERVER_HOSTBUTTON_GFX_URL, //available when connected, always up-to-date - VIRTUALSERVER_QUERYCLIENTS_ONLINE, //only available on request (=> requestServerVariables) - VIRTUALSERVER_DOWNLOAD_QUOTA, //only available on request (=> requestServerVariables) - VIRTUALSERVER_UPLOAD_QUOTA, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MONTH_BYTES_DOWNLOADED, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MONTH_BYTES_UPLOADED, //only available on request (=> requestServerVariables) - VIRTUALSERVER_TOTAL_BYTES_DOWNLOADED, //only available on request (=> requestServerVariables) - VIRTUALSERVER_TOTAL_BYTES_UPLOADED, //only available on request (=> requestServerVariables) - VIRTUALSERVER_PORT, //only available on request (=> requestServerVariables) - VIRTUALSERVER_AUTOSTART, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MACHINE_ID, //only available on request (=> requestServerVariables) - VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL, //only available on request (=> requestServerVariables) - VIRTUALSERVER_LOG_CLIENT, //only available on request (=> requestServerVariables) - VIRTUALSERVER_LOG_QUERY, //only available on request (=> requestServerVariables) - VIRTUALSERVER_LOG_CHANNEL, //only available on request (=> requestServerVariables) - VIRTUALSERVER_LOG_PERMISSIONS, //only available on request (=> requestServerVariables) - VIRTUALSERVER_LOG_SERVER, //only available on request (=> requestServerVariables) - VIRTUALSERVER_LOG_FILETRANSFER, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MIN_CLIENT_VERSION, //only available on request (=> requestServerVariables) - VIRTUALSERVER_NAME_PHONETIC, //available when connected, always up-to-date - VIRTUALSERVER_ICON_ID, //available when connected, always up-to-date - VIRTUALSERVER_RESERVED_SLOTS, //available when connected, always up-to-date - VIRTUALSERVER_TOTAL_PACKETLOSS_SPEECH, //only available on request (=> requestServerVariables) - VIRTUALSERVER_TOTAL_PACKETLOSS_KEEPALIVE, //only available on request (=> requestServerVariables) - VIRTUALSERVER_TOTAL_PACKETLOSS_CONTROL, //only available on request (=> requestServerVariables) - VIRTUALSERVER_TOTAL_PACKETLOSS_TOTAL, //only available on request (=> requestServerVariables) - VIRTUALSERVER_TOTAL_PING, //only available on request (=> requestServerVariables) - VIRTUALSERVER_IP, //internal use | contains comma separated ip list - VIRTUALSERVER_WEBLIST_ENABLED, //only available on request (=> requestServerVariables) - VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY, //internal use - VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY, //available when connected - VIRTUALSERVER_HOSTBANNER_MODE, //available when connected, always up-to-date - VIRTUALSERVER_CHANNEL_TEMP_DELETE_DELAY_DEFAULT, //available when connected, always up-to-date - VIRTUALSERVER_MIN_ANDROID_VERSION, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MIN_IOS_VERSION, //only available on request (=> requestServerVariables) - VIRTUALSERVER_MIN_WINPHONE_VERSION, //only available on request (=> requestServerVariables) - VIRTUALSERVER_NICKNAME, //available when connected, always up-to-date - VIRTUALSERVER_ACCOUNTING_TOKEN, //internal use | contains base64 encoded token data - VIRTUALSERVER_PROTOCOL_VERIFY_KEYPAIR, //internal use - VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_PLUGIN_BLOCK, //only available on request (=> requestServerVariables) - VIRTUALSERVER_ENDMARKER_RARE -}; - -enum ChannelPropertiesRare { - CHANNEL_DUMMY_3=CHANNEL_ENDMARKER, - CHANNEL_DUMMY_4, - CHANNEL_DUMMY_5, - CHANNEL_DUMMY_6, - CHANNEL_DUMMY_7, - CHANNEL_FLAG_MAXCLIENTS_UNLIMITED, //Available for all channels that are "in view", always up-to-date - CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED,//Available for all channels that are "in view", always up-to-date - CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED,//Available for all channels that are "in view", always up-to-date - CHANNEL_FLAG_ARE_SUBSCRIBED, //Only available client side, stores whether we are subscribed to this channel - CHANNEL_FILEPATH, //not available client side, the folder used for file-transfers for this channel - CHANNEL_NEEDED_TALK_POWER, //Available for all channels that are "in view", always up-to-date - CHANNEL_FORCED_SILENCE, //Available for all channels that are "in view", always up-to-date - CHANNEL_NAME_PHONETIC, //Available for all channels that are "in view", always up-to-date - CHANNEL_ICON_ID, //Available for all channels that are "in view", always up-to-date - CHANNEL_BANNER_GFX_URL, //Available for all channels that are "in view", always up-to-date - CHANNEL_BANNER_MODE, //Available for all channels that are "in view", always up-to-date - CHANNEL_PERMISSION_HINTS, - CHANNEL_ENDMARKER_RARE, - CHANNEL_DELETE_DELAY_DEADLINE = 127 //(for clientlibv2) expected delete time in monotonic clock seconds or 0 if nothing is expected -}; - -enum ClientPropertiesRare { - CLIENT_DUMMY_4 = CLIENT_ENDMARKER, - CLIENT_DUMMY_5, - CLIENT_DUMMY_6, - CLIENT_DUMMY_7, - CLIENT_DUMMY_8, - CLIENT_DUMMY_9, - CLIENT_KEY_OFFSET, //internal use - CLIENT_LAST_VAR_REQUEST, //internal use - CLIENT_LOGIN_NAME, //used for serverquery clients, makes no sense on normal clients currently - CLIENT_LOGIN_PASSWORD, //used for serverquery clients, makes no sense on normal clients currently - CLIENT_DATABASE_ID, //automatically up-to-date for any client "in view", only valid with PERMISSION feature, holds database client id - CLIENT_CHANNEL_GROUP_ID, //automatically up-to-date for any client "in view", only valid with PERMISSION feature, holds database client id - CLIENT_SERVERGROUPS, //automatically up-to-date for any client "in view", only valid with PERMISSION feature, holds all servergroups client belongs too - CLIENT_CREATED, //this needs to be requested (=> requestClientVariables), first time this client connected to this server - CLIENT_LASTCONNECTED, //this needs to be requested (=> requestClientVariables), last time this client connected to this server - CLIENT_TOTALCONNECTIONS, //this needs to be requested (=> requestClientVariables), how many times this client connected to this server - CLIENT_AWAY, //automatically up-to-date for any client "in view", this clients away status - CLIENT_AWAY_MESSAGE, //automatically up-to-date for any client "in view", this clients away message - CLIENT_TYPE, //automatically up-to-date for any client "in view", determines if this is a real client or a server-query connection - CLIENT_FLAG_AVATAR, //automatically up-to-date for any client "in view", this client got an avatar - CLIENT_TALK_POWER, //automatically up-to-date for any client "in view", only valid with PERMISSION feature, holds database client id - CLIENT_TALK_REQUEST, //automatically up-to-date for any client "in view", only valid with PERMISSION feature, holds timestamp where client requested to talk - CLIENT_TALK_REQUEST_MSG, //automatically up-to-date for any client "in view", only valid with PERMISSION feature, holds matter for the request - CLIENT_DESCRIPTION, //automatically up-to-date for any client "in view" - CLIENT_IS_TALKER, //automatically up-to-date for any client "in view" - CLIENT_MONTH_BYTES_UPLOADED, //this needs to be requested (=> requestClientVariables) - CLIENT_MONTH_BYTES_DOWNLOADED, //this needs to be requested (=> requestClientVariables) - CLIENT_TOTAL_BYTES_UPLOADED, //this needs to be requested (=> requestClientVariables) - CLIENT_TOTAL_BYTES_DOWNLOADED, //this needs to be requested (=> requestClientVariables) - CLIENT_IS_PRIORITY_SPEAKER, //automatically up-to-date for any client "in view" - CLIENT_UNREAD_MESSAGES, //automatically up-to-date for any client "in view" - CLIENT_NICKNAME_PHONETIC, //automatically up-to-date for any client "in view" - CLIENT_NEEDED_SERVERQUERY_VIEW_POWER, //automatically up-to-date for any client "in view" - CLIENT_DEFAULT_TOKEN, //only usable for ourself, the default token we used to connect on our last connection attempt - CLIENT_ICON_ID, //automatically up-to-date for any client "in view" - CLIENT_IS_CHANNEL_COMMANDER, //automatically up-to-date for any client "in view" - CLIENT_COUNTRY, //automatically up-to-date for any client "in view" - CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID, //automatically up-to-date for any client "in view", only valid with PERMISSION feature, contains channel_id where the channel_group_id is set from - CLIENT_BADGES, //automatically up-to-date for any client "in view", stores icons for partner badges - CLIENT_MYTEAMSPEAK_ID, //automatically up-to-date for any client "in view", stores myteamspeak id - CLIENT_INTEGRATIONS, //automatically up-to-date for any client "in view", stores integrations - CLIENT_ACTIVE_INTEGRATIONS_INFO, //stores info from the myts server and contains the subscription info - CLIENT_MYTS_AVATAR, - CLIENT_SIGNED_BADGES, - CLIENT_PERMISSION_HINTS, - CLIENT_ENDMARKER_RARE, - CLIENT_HW_ID = 127 //(for clientlibv2) unique hardware id -}; - -enum ConnectionPropertiesRare { - CONNECTION_DUMMY_0= CONNECTION_ENDMARKER, - CONNECTION_DUMMY_1, - CONNECTION_DUMMY_2, - CONNECTION_DUMMY_3, - CONNECTION_DUMMY_4, - CONNECTION_DUMMY_5, - CONNECTION_DUMMY_6, - CONNECTION_DUMMY_7, - CONNECTION_DUMMY_8, - CONNECTION_DUMMY_9, - CONNECTION_FILETRANSFER_BANDWIDTH_SENT, //how many bytes per second are currently being sent by file transfers - CONNECTION_FILETRANSFER_BANDWIDTH_RECEIVED, //how many bytes per second are currently being received by file transfers - CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL, //how many bytes we received in total through file transfers - CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL, //how many bytes we sent in total through file transfers - CONNECTION_ENDMARKER_RARE, -}; - -enum BBCodeTags { - BBCodeTag_B = 0x00000001, - BBCodeTag_I = 0x00000002, - BBCodeTag_U = 0x00000004, - BBCodeTag_S = 0x00000008, - BBCodeTag_SUP = 0x00000010, - BBCodeTag_SUB = 0x00000020, - BBCodeTag_COLOR = 0x00000040, - BBCodeTag_SIZE = 0x00000080, - BBCodeTag_group_text = 0x000000FF, - - BBCodeTag_LEFT = 0x00001000, - BBCodeTag_RIGHT = 0x00002000, - BBCodeTag_CENTER = 0x00004000, - BBCodeTag_group_align = 0x00007000, - - BBCodeTag_URL = 0x00010000, - BBCodeTag_IMAGE = 0x00020000, - BBCodeTag_HR = 0x00040000, - - BBCodeTag_LIST = 0x00100000, - BBCodeTag_LISTITEM = 0x00200000, - BBCodeTag_group_list = 0x00300000, - - BBCodeTag_TABLE = 0x00400000, - BBCodeTag_TR = 0x00800000, - BBCodeTag_TH = 0x01000000, - BBCodeTag_TD = 0x02000000, - BBCodeTag_group_table = 0x03C00000, - - BBCodeTag_def_simple = BBCodeTag_B | BBCodeTag_I | BBCodeTag_U | BBCodeTag_S | BBCodeTag_SUP | BBCodeTag_SUB |BBCodeTag_COLOR | BBCodeTag_URL, - BBCodeTag_def_simple_Img = BBCodeTag_def_simple | BBCodeTag_IMAGE, - BBCodeTag_def_extended = BBCodeTag_group_text | BBCodeTag_group_align | BBCodeTag_URL | BBCodeTag_IMAGE | BBCodeTag_HR | BBCodeTag_group_list | BBCodeTag_group_table, -}; - -enum LicenseIssue { - Blacklisted = 0, - Greylisted -}; - -enum MytsDataUnsetFlags { - MytsDataUnsetFlag_None = 0, - MytsDataUnsetFlag_Badges = 1, - MytsDataUnsetFlag_Avatar = 1 << 1, - - MytsDataUnsetFlag_All = MytsDataUnsetFlag_Badges | MytsDataUnsetFlag_Avatar // make sure "all" really contains all flags -}; - -typedef int(*ExtraBBCodeValidator)(void* userparam, const char* tag, const char* paramValue, int paramValueSize, const char* childValue, int childValueSize); -typedef const char* (*ExtraBBCodeParamTransform)(void* userparam, const char* tag, const char* paramValue); - -#endif //PUBLIC_RARE_DEFINITIONS_H diff --git a/pluginsdk/include/ts3_functions.h b/pluginsdk/include/ts3_functions.h deleted file mode 100644 index 348a4b1..0000000 --- a/pluginsdk/include/ts3_functions.h +++ /dev/null @@ -1,305 +0,0 @@ -#ifndef TS3_FUNCTIONS_H -#define TS3_FUNCTIONS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "teamspeak/clientlib_publicdefinitions.h" -#include "teamspeak/public_definitions.h" -#include "plugin_definitions.h" - -/* Functions exported to plugin from main binary */ -struct TS3Functions { - unsigned int (*getClientLibVersion)(char** result); - unsigned int (*getClientLibVersionNumber)(uint64* result); - unsigned int (*spawnNewServerConnectionHandler)(int port, uint64* result); - unsigned int (*destroyServerConnectionHandler)(uint64 serverConnectionHandlerID); - - /* Error handling */ - unsigned int (*getErrorMessage)(unsigned int errorCode, char** error); - - /* Memory management */ - unsigned int (*freeMemory)(void* pointer); - - /* Logging */ - unsigned int (*logMessage)(const char* logMessage, enum LogLevel severity, const char* channel, uint64 logID); - - /* Sound */ - unsigned int (*getPlaybackDeviceList)(const char* modeID, char**** result); - unsigned int (*getPlaybackModeList)(char*** result); - unsigned int (*getCaptureDeviceList)(const char* modeID, char**** result); - unsigned int (*getCaptureModeList)(char*** result); - unsigned int (*getDefaultPlaybackDevice)(const char* modeID, char*** result); - unsigned int (*getDefaultPlayBackMode)(char** result); - unsigned int (*getDefaultCaptureDevice)(const char* modeID, char*** result); - unsigned int (*getDefaultCaptureMode)(char** result); - unsigned int (*openPlaybackDevice)(uint64 serverConnectionHandlerID, const char* modeID, const char* playbackDevice); - unsigned int (*openCaptureDevice)(uint64 serverConnectionHandlerID, const char* modeID, const char* captureDevice); - unsigned int (*getCurrentPlaybackDeviceName)(uint64 serverConnectionHandlerID, char** result, int* isDefault); - unsigned int (*getCurrentPlayBackMode)(uint64 serverConnectionHandlerID, char** result); - unsigned int (*getCurrentCaptureDeviceName)(uint64 serverConnectionHandlerID, char** result, int* isDefault); - unsigned int (*getCurrentCaptureMode)(uint64 serverConnectionHandlerID, char** result); - unsigned int (*initiateGracefulPlaybackShutdown)(uint64 serverConnectionHandlerID); - unsigned int (*closePlaybackDevice)(uint64 serverConnectionHandlerID); - unsigned int (*closeCaptureDevice)(uint64 serverConnectionHandlerID); - unsigned int (*activateCaptureDevice)(uint64 serverConnectionHandlerID); - unsigned int (*playWaveFileHandle)(uint64 serverConnectionHandlerID, const char* path, int loop, uint64* waveHandle); - unsigned int (*pauseWaveFileHandle)(uint64 serverConnectionHandlerID, uint64 waveHandle, int pause); - unsigned int (*closeWaveFileHandle)(uint64 serverConnectionHandlerID, uint64 waveHandle); - unsigned int (*playWaveFile)(uint64 serverConnectionHandlerID, const char* path); - unsigned int (*registerCustomDevice)(const char* deviceID, const char* deviceDisplayName, int capFrequency, int capChannels, int playFrequency, int playChannels); - unsigned int (*unregisterCustomDevice)(const char* deviceID); - unsigned int (*processCustomCaptureData)(const char* deviceName, const short* buffer, int samples); - unsigned int (*acquireCustomPlaybackData)(const char* deviceName, short* buffer, int samples); - - /* Preprocessor */ - unsigned int (*getPreProcessorInfoValueFloat)(uint64 serverConnectionHandlerID, const char* ident, float* result); - unsigned int (*getPreProcessorConfigValue)(uint64 serverConnectionHandlerID, const char* ident, char** result); - unsigned int (*setPreProcessorConfigValue)(uint64 serverConnectionHandlerID, const char* ident, const char* value); - - /* Encoder */ - unsigned int (*getEncodeConfigValue)(uint64 serverConnectionHandlerID, const char* ident, char** result); - - /* Playback */ - unsigned int (*getPlaybackConfigValueAsFloat)(uint64 serverConnectionHandlerID, const char* ident, float* result); - unsigned int (*setPlaybackConfigValue)(uint64 serverConnectionHandlerID, const char* ident, const char* value); - unsigned int (*setClientVolumeModifier)(uint64 serverConnectionHandlerID, anyID clientID, float value); - - /* Recording status */ - unsigned int (*startVoiceRecording)(uint64 serverConnectionHandlerID); - unsigned int (*stopVoiceRecording)(uint64 serverConnectionHandlerID); - - /* 3d sound positioning */ - unsigned int (*systemset3DListenerAttributes) (uint64 serverConnectionHandlerID, const TS3_VECTOR* position, const TS3_VECTOR* forward, const TS3_VECTOR* up); - unsigned int (*set3DWaveAttributes) (uint64 serverConnectionHandlerID, uint64 waveHandle, const TS3_VECTOR* position); - unsigned int (*systemset3DSettings) (uint64 serverConnectionHandlerID, float distanceFactor, float rolloffScale); - unsigned int (*channelset3DAttributes) (uint64 serverConnectionHandlerID, anyID clientID, const TS3_VECTOR* position); - - /* Interaction with the server */ - unsigned int (*startConnection)(uint64 serverConnectionHandlerID, const char* identity, const char* ip, unsigned int port, const char* nickname, - const char** defaultChannelArray, const char* defaultChannelPassword, const char* serverPassword); - unsigned int (*stopConnection)(uint64 serverConnectionHandlerID, const char* quitMessage); - unsigned int (*requestClientMove)(uint64 serverConnectionHandlerID, anyID clientID, uint64 newChannelID, const char* password, const char* returnCode); - unsigned int (*requestClientVariables)(uint64 serverConnectionHandlerID, anyID clientID, const char* returnCode); - unsigned int (*requestClientKickFromChannel)(uint64 serverConnectionHandlerID, anyID clientID, const char* kickReason, const char* returnCode); - unsigned int (*requestClientKickFromServer)(uint64 serverConnectionHandlerID, anyID clientID, const char* kickReason, const char* returnCode); - unsigned int (*requestChannelDelete)(uint64 serverConnectionHandlerID, uint64 channelID, int force, const char* returnCode); - unsigned int (*requestChannelMove)(uint64 serverConnectionHandlerID, uint64 channelID, uint64 newChannelParentID, uint64 newChannelOrder, const char* returnCode); - unsigned int (*requestSendPrivateTextMsg)(uint64 serverConnectionHandlerID, const char* message, anyID targetClientID, const char* returnCode); - unsigned int (*requestSendChannelTextMsg)(uint64 serverConnectionHandlerID, const char* message, uint64 targetChannelID, const char* returnCode); - unsigned int (*requestSendServerTextMsg)(uint64 serverConnectionHandlerID, const char* message, const char* returnCode); - unsigned int (*requestConnectionInfo)(uint64 serverConnectionHandlerID, anyID clientID, const char* returnCode); - unsigned int (*requestClientSetWhisperList)(uint64 serverConnectionHandlerID, anyID clientID, const uint64* targetChannelIDArray, const anyID* targetClientIDArray, const char* returnCode); - unsigned int (*requestChannelSubscribe)(uint64 serverConnectionHandlerID, const uint64* channelIDArray, const char* returnCode); - unsigned int (*requestChannelSubscribeAll)(uint64 serverConnectionHandlerID, const char* returnCode); - unsigned int (*requestChannelUnsubscribe)(uint64 serverConnectionHandlerID, const uint64* channelIDArray, const char* returnCode); - unsigned int (*requestChannelUnsubscribeAll)(uint64 serverConnectionHandlerID, const char* returnCode); - unsigned int (*requestChannelDescription)(uint64 serverConnectionHandlerID, uint64 channelID, const char* returnCode); - unsigned int (*requestMuteClients)(uint64 serverConnectionHandlerID, const anyID* clientIDArray, const char* returnCode); - unsigned int (*requestUnmuteClients)(uint64 serverConnectionHandlerID, const anyID* clientIDArray, const char* returnCode); - unsigned int (*requestClientPoke)(uint64 serverConnectionHandlerID, anyID clientID, const char* message, const char* returnCode); - unsigned int (*requestClientIDs)(uint64 serverConnectionHandlerID, const char* clientUniqueIdentifier, const char* returnCode); - unsigned int (*clientChatClosed)(uint64 serverConnectionHandlerID, const char* clientUniqueIdentifier, anyID clientID, const char* returnCode); - unsigned int (*clientChatComposing)(uint64 serverConnectionHandlerID, anyID clientID, const char* returnCode); - unsigned int (*requestServerTemporaryPasswordAdd)(uint64 serverConnectionHandlerID, const char* password, const char* description, uint64 duration, uint64 targetChannelID, const char* targetChannelPW, const char* returnCode); - unsigned int (*requestServerTemporaryPasswordDel)(uint64 serverConnectionHandlerID, const char* password, const char* returnCode); - unsigned int (*requestServerTemporaryPasswordList)(uint64 serverConnectionHandlerID, const char* returnCode); - - /* Access clientlib information */ - - /* Query own client ID */ - unsigned int (*getClientID)(uint64 serverConnectionHandlerID, anyID* result); - - /* Client info */ - unsigned int (*getClientSelfVariableAsInt)(uint64 serverConnectionHandlerID, size_t flag, int* result); - unsigned int (*getClientSelfVariableAsString)(uint64 serverConnectionHandlerID, size_t flag, char** result); - unsigned int (*setClientSelfVariableAsInt)(uint64 serverConnectionHandlerID, size_t flag, int value); - unsigned int (*setClientSelfVariableAsString)(uint64 serverConnectionHandlerID, size_t flag, const char* value); - unsigned int (*flushClientSelfUpdates)(uint64 serverConnectionHandlerID, const char* returnCode); - unsigned int (*getClientVariableAsInt)(uint64 serverConnectionHandlerID, anyID clientID, size_t flag, int* result); - unsigned int (*getClientVariableAsUInt64)(uint64 serverConnectionHandlerID, anyID clientID, size_t flag, uint64* result); - unsigned int (*getClientVariableAsString)(uint64 serverConnectionHandlerID, anyID clientID, size_t flag, char** result); - unsigned int (*getClientList)(uint64 serverConnectionHandlerID, anyID** result); - unsigned int (*getChannelOfClient)(uint64 serverConnectionHandlerID, anyID clientID, uint64* result); - - /* Channel info */ - unsigned int (*getChannelVariableAsInt)(uint64 serverConnectionHandlerID, uint64 channelID, size_t flag, int* result); - unsigned int (*getChannelVariableAsUInt64)(uint64 serverConnectionHandlerID, uint64 channelID, size_t flag, uint64* result); - unsigned int (*getChannelVariableAsString)(uint64 serverConnectionHandlerID, uint64 channelID, size_t flag, char** result); - unsigned int (*getChannelIDFromChannelNames)(uint64 serverConnectionHandlerID, char** channelNameArray, uint64* result); - unsigned int (*setChannelVariableAsInt)(uint64 serverConnectionHandlerID, uint64 channelID, size_t flag, int value); - unsigned int (*setChannelVariableAsUInt64)(uint64 serverConnectionHandlerID, uint64 channelID, size_t flag, uint64 value); - unsigned int (*setChannelVariableAsString)(uint64 serverConnectionHandlerID, uint64 channelID, size_t flag, const char* value); - unsigned int (*flushChannelUpdates)(uint64 serverConnectionHandlerID, uint64 channelID, const char* returnCode); - unsigned int (*flushChannelCreation)(uint64 serverConnectionHandlerID, uint64 channelParentID, const char* returnCode); - unsigned int (*getChannelList)(uint64 serverConnectionHandlerID, uint64** result); - unsigned int (*getChannelClientList)(uint64 serverConnectionHandlerID, uint64 channelID, anyID** result); - unsigned int (*getParentChannelOfChannel)(uint64 serverConnectionHandlerID, uint64 channelID, uint64* result); - - /* Server info */ - unsigned int (*getServerConnectionHandlerList)(uint64** result); - unsigned int (*getServerVariableAsInt)(uint64 serverConnectionHandlerID, size_t flag, int* result); - unsigned int (*getServerVariableAsUInt64)(uint64 serverConnectionHandlerID, size_t flag, uint64* result); - unsigned int (*getServerVariableAsString)(uint64 serverConnectionHandlerID, size_t flag, char** result); - unsigned int (*requestServerVariables)(uint64 serverConnectionHandlerID); - - /* Connection info */ - unsigned int (*getConnectionStatus)(uint64 serverConnectionHandlerID, int* result); - unsigned int (*getConnectionVariableAsUInt64)(uint64 serverConnectionHandlerID, anyID clientID, size_t flag, uint64* result); - unsigned int (*getConnectionVariableAsDouble)(uint64 serverConnectionHandlerID, anyID clientID, size_t flag, double* result); - unsigned int (*getConnectionVariableAsString)(uint64 serverConnectionHandlerID, anyID clientID, size_t flag, char** result); - unsigned int (*cleanUpConnectionInfo)(uint64 serverConnectionHandlerID, anyID clientID); - - /* Client related */ - unsigned int (*requestClientDBIDfromUID)(uint64 serverConnectionHandlerID, const char* clientUniqueIdentifier, const char* returnCode); - unsigned int (*requestClientNamefromUID)(uint64 serverConnectionHandlerID, const char* clientUniqueIdentifier, const char* returnCode); - unsigned int (*requestClientNamefromDBID)(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, const char* returnCode); - unsigned int (*requestClientEditDescription)(uint64 serverConnectionHandlerID, anyID clientID, const char* clientDescription, const char* returnCode); - unsigned int (*requestClientSetIsTalker)(uint64 serverConnectionHandlerID, anyID clientID, int isTalker, const char* returnCode); - unsigned int (*requestIsTalker)(uint64 serverConnectionHandlerID, int isTalkerRequest, const char* isTalkerRequestMessage, const char* returnCode); - - /* Plugin related */ - unsigned int (*requestSendClientQueryCommand)(uint64 serverConnectionHandlerID, const char* command, const char* returnCode); - - /* Filetransfer */ - unsigned int (*getTransferFileName)(anyID transferID, char** result); - unsigned int (*getTransferFilePath)(anyID transferID, char** result); - unsigned int (*getTransferFileSize)(anyID transferID, uint64* result); - unsigned int (*getTransferFileSizeDone)(anyID transferID, uint64* result); - unsigned int (*isTransferSender)(anyID transferID, int* result); /* 1 == upload, 0 == download */ - unsigned int (*getTransferStatus)(anyID transferID, int* result); - unsigned int (*getCurrentTransferSpeed)(anyID transferID, float* result); - unsigned int (*getAverageTransferSpeed)(anyID transferID, float* result); - unsigned int (*getTransferRunTime)(anyID transferID, uint64* result); - unsigned int (*sendFile)(uint64 serverConnectionHandlerID, uint64 channelID, const char* channelPW, const char* file, int overwrite, int resume, const char* sourceDirectory, anyID* result, const char* returnCode); - unsigned int (*requestFile)(uint64 serverConnectionHandlerID, uint64 channelID, const char* channelPW, const char* file, int overwrite, int resume, const char* destinationDirectory, anyID* result, const char* returnCode); - unsigned int (*haltTransfer)(uint64 serverConnectionHandlerID, anyID transferID, int deleteUnfinishedFile, const char* returnCode); - unsigned int (*requestFileList)(uint64 serverConnectionHandlerID, uint64 channelID, const char* channelPW, const char* path, const char* returnCode); - unsigned int (*requestFileInfo)(uint64 serverConnectionHandlerID, uint64 channelID, const char* channelPW, const char* file, const char* returnCode); - unsigned int (*requestDeleteFile)(uint64 serverConnectionHandlerID, uint64 channelID, const char* channelPW, const char** file, const char* returnCode); - unsigned int (*requestCreateDirectory)(uint64 serverConnectionHandlerID, uint64 channelID, const char* channelPW, const char* directoryPath, const char* returnCode); - unsigned int (*requestRenameFile)(uint64 serverConnectionHandlerID, uint64 fromChannelID, const char* channelPW, uint64 toChannelID, const char* toChannelPW, const char* oldFile, const char* newFile, const char* returnCode); - - /* Offline message management */ - unsigned int (*requestMessageAdd)(uint64 serverConnectionHandlerID, const char* toClientUID, const char* subject, const char* message, const char* returnCode); - unsigned int (*requestMessageDel)(uint64 serverConnectionHandlerID, uint64 messageID, const char* returnCode); - unsigned int (*requestMessageGet)(uint64 serverConnectionHandlerID, uint64 messageID, const char* returnCode); - unsigned int (*requestMessageList)(uint64 serverConnectionHandlerID, const char* returnCode); - unsigned int (*requestMessageUpdateFlag)(uint64 serverConnectionHandlerID, uint64 messageID, int flag, const char* returnCode); - - /* Interacting with the server - confirming passwords */ - unsigned int (*verifyServerPassword)(uint64 serverConnectionHandlerID, const char* serverPassword, const char* returnCode); - unsigned int (*verifyChannelPassword)(uint64 serverConnectionHandlerID, uint64 channelID, const char* channelPassword, const char* returnCode); - - /* Interacting with the server - banning */ - unsigned int (*banclient)(uint64 serverConnectionHandlerID, anyID clientID, uint64 timeInSeconds, const char* banReason, const char* returnCode); - unsigned int (*banadd)(uint64 serverConnectionHandlerID, const char* ipRegExp, const char* nameRegexp, const char* uniqueIdentity, const char* mytsID, uint64 timeInSeconds, const char* banReason, const char* returnCode); - unsigned int (*banclientdbid)(uint64 serverConnectionHandlerID, uint64 clientDBID, uint64 timeInSeconds, const char* banReason, const char* returnCode); - unsigned int (*bandel)(uint64 serverConnectionHandlerID, uint64 banID, const char* returnCode); - unsigned int (*bandelall)(uint64 serverConnectionHandlerID, const char* returnCode); - unsigned int (*requestBanList)(uint64 serverConnectionHandlerID, uint64 start, unsigned int duration, const char* returnCode); - - /* Interacting with the server - complain */ - unsigned int (*requestComplainAdd)(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, const char* complainReason, const char* returnCode); - unsigned int (*requestComplainDel)(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, uint64 fromClientDatabaseID, const char* returnCode); - unsigned int (*requestComplainDelAll)(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, const char* returnCode); - unsigned int (*requestComplainList)(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, const char* returnCode); - - /* Permissions */ - unsigned int (*requestServerGroupList)(uint64 serverConnectionHandlerID, const char* returnCode); - unsigned int (*requestServerGroupAdd)(uint64 serverConnectionHandlerID, const char* groupName, int groupType, const char* returnCode); - unsigned int (*requestServerGroupDel)(uint64 serverConnectionHandlerID, uint64 serverGroupID, int force, const char* returnCode); - unsigned int (*requestServerGroupAddClient)(uint64 serverConnectionHandlerID, uint64 serverGroupID, uint64 clientDatabaseID, const char* returnCode); - unsigned int (*requestServerGroupDelClient)(uint64 serverConnectionHandlerID, uint64 serverGroupID, uint64 clientDatabaseID, const char* returnCode); - unsigned int (*requestServerGroupsByClientID)(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, const char* returnCode); - unsigned int (*requestServerGroupAddPerm)(uint64 serverConnectionHandlerID, uint64 serverGroupID, int continueonerror, const unsigned int* permissionIDArray, const int* permissionValueArray, const int* permissionNegatedArray, const int* permissionSkipArray, int arraySize, const char* returnCode); - unsigned int (*requestServerGroupDelPerm)(uint64 serverConnectionHandlerID, uint64 serverGroupID, int continueOnError, const unsigned int* permissionIDArray, int arraySize, const char* returnCode); - unsigned int (*requestServerGroupPermList)(uint64 serverConnectionHandlerID, uint64 serverGroupID, const char* returnCode); - unsigned int (*requestServerGroupClientList)(uint64 serverConnectionHandlerID, uint64 serverGroupID, int withNames, const char* returnCode); - unsigned int (*requestChannelGroupList)(uint64 serverConnectionHandlerID, const char* returnCode); - unsigned int (*requestChannelGroupAdd)(uint64 serverConnectionHandlerID, const char* groupName, int groupType, const char* returnCode); - unsigned int (*requestChannelGroupDel)(uint64 serverConnectionHandlerID, uint64 channelGroupID, int force, const char* returnCode); - unsigned int (*requestChannelGroupAddPerm)(uint64 serverConnectionHandlerID, uint64 channelGroupID, int continueonerror, const unsigned int* permissionIDArray, const int* permissionValueArray, int arraySize, const char* returnCode); - unsigned int (*requestChannelGroupDelPerm)(uint64 serverConnectionHandlerID, uint64 channelGroupID, int continueOnError, const unsigned int* permissionIDArray, int arraySize, const char* returnCode); - unsigned int (*requestChannelGroupPermList)(uint64 serverConnectionHandlerID, uint64 channelGroupID, const char* returnCode); - unsigned int (*requestSetClientChannelGroup)(uint64 serverConnectionHandlerID, const uint64* channelGroupIDArray, const uint64* channelIDArray, const uint64* clientDatabaseIDArray, int arraySize, const char* returnCode); - unsigned int (*requestChannelAddPerm)(uint64 serverConnectionHandlerID, uint64 channelID, const unsigned int* permissionIDArray, const int* permissionValueArray, int arraySize, const char* returnCode); - unsigned int (*requestChannelDelPerm)(uint64 serverConnectionHandlerID, uint64 channelID, const unsigned int* permissionIDArray, int arraySize, const char* returnCode); - unsigned int (*requestChannelPermList)(uint64 serverConnectionHandlerID, uint64 channelID, const char* returnCode); - unsigned int (*requestClientAddPerm)(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, const unsigned int* permissionIDArray, const int* permissionValueArray, const int* permissionSkipArray, int arraySize, const char* returnCode); - unsigned int (*requestClientDelPerm)(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, const unsigned int* permissionIDArray, int arraySize, const char* returnCode); - unsigned int (*requestClientPermList)(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, const char* returnCode); - unsigned int (*requestChannelClientAddPerm)(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID, const unsigned int* permissionIDArray, const int* permissionValueArray, int arraySize, const char* returnCode); - unsigned int (*requestChannelClientDelPerm)(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID, const unsigned int* permissionIDArray, int arraySize, const char* returnCode); - unsigned int (*requestChannelClientPermList)(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID, const char* returnCode); - unsigned int (*privilegeKeyUse)(uint64 serverConnectionHandler, const char* tokenKey, const char* returnCode); - unsigned int (*requestPermissionList)(uint64 serverConnectionHandler, const char* returnCode); - unsigned int (*requestPermissionOverview)(uint64 serverConnectionHandler, uint64 clientDBID, uint64 channelID, const char* returnCode); - - /* Helper Functions */ - unsigned int (*clientPropertyStringToFlag)(const char* clientPropertyString, size_t* resultFlag); - unsigned int (*channelPropertyStringToFlag)(const char* channelPropertyString, size_t* resultFlag); - unsigned int (*serverPropertyStringToFlag)(const char* serverPropertyString, size_t* resultFlag); - - /* Client functions */ - void (*getAppPath)(char* path, size_t maxLen); - void (*getResourcesPath)(char* path, size_t maxLen); - void (*getConfigPath)(char* path, size_t maxLen); - void (*getPluginPath)(char* path, size_t maxLen, const char* pluginID); - uint64 (*getCurrentServerConnectionHandlerID)(); - void (*printMessage)(uint64 serverConnectionHandlerID, const char* message, enum PluginMessageTarget messageTarget); - void (*printMessageToCurrentTab)(const char* message); - void (*urlsToBB)(const char* text, char* result, size_t maxLen); - void (*sendPluginCommand)(uint64 serverConnectionHandlerID, const char* pluginID, const char* command, int targetMode, const anyID* targetIDs, const char* returnCode); - void (*getDirectories)(const char* path, char* result, size_t maxLen); - unsigned int (*getServerConnectInfo)(uint64 scHandlerID, char* host, unsigned short* port, char* password, size_t maxLen); - unsigned int (*getChannelConnectInfo)(uint64 scHandlerID, uint64 channelID, char* path, char* password, size_t maxLen); - void (*createReturnCode)(const char* pluginID, char* returnCode, size_t maxLen); - unsigned int (*requestInfoUpdate)(uint64 scHandlerID, enum PluginItemType itemType, uint64 itemID); - uint64 (*getServerVersion)(uint64 scHandlerID); - unsigned int (*isWhispering)(uint64 scHandlerID, anyID clientID, int* result); - unsigned int (*isReceivingWhisper)(uint64 scHandlerID, anyID clientID, int* result); - unsigned int (*getAvatar)(uint64 scHandlerID, anyID clientID, char* result, size_t maxLen); - void (*setPluginMenuEnabled)(const char* pluginID, int menuID, int enabled); - void (*showHotkeySetup)(); - void (*requestHotkeyInputDialog)(const char* pluginID, const char* keyword, int isDown, void* qParentWindow); - unsigned int (*getHotkeyFromKeyword)(const char* pluginID, const char** keywords, char** hotkeys, size_t arrayLen, size_t hotkeyBufSize); - unsigned int (*getClientDisplayName)(uint64 scHandlerID, anyID clientID, char* result, size_t maxLen); - unsigned int (*getBookmarkList)(struct PluginBookmarkList** list); - unsigned int (*getProfileList)(enum PluginGuiProfile profile, int* defaultProfileIdx, char*** result); - unsigned int (*guiConnect)(enum PluginConnectTab connectTab, const char* serverLabel, const char* serverAddress, const char* serverPassword, const char* nickname, const char* channel, const char* channelPassword, const char* captureProfile, const char* playbackProfile, const char* hotkeyProfile, const char* soundProfile, const char* userIdentity, const char* oneTimeKey, const char* phoneticName, uint64* scHandlerID); - unsigned int (*guiConnectBookmark)(enum PluginConnectTab connectTab, const char* bookmarkuuid, uint64* scHandlerID); - unsigned int (*createBookmark)(const char* bookmarkuuid, const char* serverLabel, const char* serverAddress, const char* serverPassword, const char* nickname, const char* channel, const char* channelPassword, const char* captureProfile, const char* playbackProfile, const char* hotkeyProfile, const char* soundProfile, const char* uniqueUserId, const char* oneTimeKey, const char* phoneticName); - unsigned int (*getPermissionIDByName)(uint64 serverConnectionHandlerID, const char* permissionName, unsigned int* result); - unsigned int (*getClientNeededPermission)(uint64 serverConnectionHandlerID, const char* permissionName, int* result); - void (*notifyKeyEvent)(const char *pluginID, const char *keyIdentifier, int up_down); - - /* Single-Track/Multi-Track recording */ - unsigned int (*startRecording)(uint64 serverConnectionHandlerID, int multitrack, int noFileSelector, const char* path); - unsigned int (*stopRecording)(uint64 serverConnectionHandlerID); - - /* Convenience functions */ - unsigned int (*requestClientsMove)(uint64 serverConnectionHandlerID, const anyID* clientIDArray, uint64 newChannelID, const char* password, const char* returnCode); - unsigned int (*requestClientsKickFromChannel)(uint64 serverConnectionHandlerID, const anyID* clientIDArray, const char* kickReason, const char* returnCode); - unsigned int (*requestClientsKickFromServer)(uint64 serverConnectionHandlerID, const anyID* clientIDArray, const char* kickReason, const char* returnCode); - unsigned int (*requestMuteClientsTemporary)(uint64 serverConnectionHandlerID, const anyID* clientIDArray, const char* returnCode); - unsigned int (*requestUnmuteClientsTemporary)(uint64 serverConnectionHandlerID, const anyID* clientIDArray, const char* returnCode); - unsigned int (*getPermissionNameByID)(uint64 scHandlerID, unsigned int permissionID, char* result, size_t max_len); - unsigned int (*clientPropertyFlagToString)(size_t clientPropertyFlag, char** resultString); - unsigned int (*channelPropertyFlagToString)(size_t channelPropertyFlag, char** resultString); - unsigned int (*serverPropertyFlagToString)(size_t serverPropertyFlag, char** resultString); - - /* Server editing */ - unsigned int (*setServerVariableAsInt)(uint64 serverConnectionHandlerID, size_t flag, int value); - unsigned int (*setServerVariableAsUInt64)(uint64 serverConnectionHandlerID, size_t flag, uint64 value); - unsigned int (*setServerVariableAsDouble)(uint64 serverConnectionHandlerID, size_t flag, double value); - unsigned int (*setServerVariableAsString)(uint64 serverConnectionHandlerID, size_t flag, const char* value); - unsigned int (*flushServerUpdates)(uint64 serverConnectionHandlerID, const char* returnCode); -}; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/pluginsdk/readme.txt b/pluginsdk/readme.txt deleted file mode 100644 index fd39c1b..0000000 --- a/pluginsdk/readme.txt +++ /dev/null @@ -1,23 +0,0 @@ -TeamSpeak 3 Plugin Software Development Kit -Copyright (c) TeamSpeak Systems GmbH - -Contents -- Demo plugin sourcecode as template for developing own plugins -- Required header files -- Clientlib documentation - -bin\plugins\ - Target build directory for the sample project. Instead you might want to configure your output directory - to the plugins directory within your TeamSpeak 3 client installation. -docs\ - Clientlib documentation -include\ - Required header files -src\ - Sourcecode of our test plugin - -We strongly recommend to build upon the test plugin. Plugins are required to export some special functions, -which already exist in the test plugin. Optional functions may be removed if not used. See code comments -for details. - -For questions please visit our forums at https://forum.teamspeak.com diff --git a/pluginsdk/src/icons/1.png b/pluginsdk/src/icons/1.png deleted file mode 100644 index aa4632b227078b84715b6281b03b83a5dd407038..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)9!^eC4MvuU%YZ^WnIRD+&iT2y zsd*(pE(61!b(>}asUS}m#}JFt$q5qI4m312Ch{>eA2w%WYx~c`!=tn$BP<~yA>zz| z0}uGF{+THh{wF;lVMmiUqp+Y}B2cEnAd4Z7nWK^a$&yCd0N)!M&KR6AU^vMuy5W`3 Qz9x_@p00i_>zopr0D#;@UH||9 diff --git a/pluginsdk/src/icons/2.png b/pluginsdk/src/icons/2.png deleted file mode 100644 index fe83f3f6ff5d25588760c97a6995b349dff5115f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 297 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)9!^d%Q&0VMdw@bbnIRD+&iT2y zsd*(pE(61!b(>}asfnI0jv*GO?_Rd&V=NRn`q4k6Lqp^>lhyPCqGp9Go!uE)1X3C13uNw~t^2cm&3v-#1*eVly#qcQm?kg^9 z4R-w3%VOm{X82w6i{QG63i`@934Q5bmh@CKI0yJkh>337ctqO#%mp3idn~2hai1t{zb@#%zbRn6vcNwdyx!sq^GN&%Q~loCIG;&Y3cv~ diff --git a/pluginsdk/src/icons/3.png b/pluginsdk/src/icons/3.png deleted file mode 100644 index bcc6557ea9bcbc4f3fe4a6e91be8b8c7c1a1e417..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)9!^d%;n_;sjzA%v%#er@=ltB< z)VvZPmw{o=x=k~I)O1f5#}JFtcP|-oA1o9&_R&9LiO5o&P13w!`3GLe&e+4cx^oZ5 zdWU-r<_TM)474RhxK7{XvH$J72^x)lX9L{9>}dSvI~q3v#NbtDnm{r-UW|Y4d2f diff --git a/pluginsdk/src/icons/t.png b/pluginsdk/src/icons/t.png deleted file mode 100644 index 3c825217fe4225daa307b20aa1ae4fa846e3faaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)9!^eSp@~87Cjo_cGD9Ltobz*Y zQ}arITn2_c>o&~S?1~L=d#Wzp$PyC4@~v| diff --git a/pluginsdk/src/plugin.c b/pluginsdk/src/plugin.c deleted file mode 100644 index 8dcbac4..0000000 --- a/pluginsdk/src/plugin.c +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * TeamSpeak 3 demo plugin - * - * Copyright (c) TeamSpeak Systems GmbH - */ - -#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) -#pragma warning (disable : 4100) /* Disable Unreferenced parameter warning */ -#include -#endif - -#include -#include -#include -#include -#include "teamspeak/public_errors.h" -#include "teamspeak/public_errors_rare.h" -#include "teamspeak/public_definitions.h" -#include "teamspeak/public_rare_definitions.h" -#include "teamspeak/clientlib_publicdefinitions.h" -#include "ts3_functions.h" -#include "plugin.h" - -static struct TS3Functions ts3Functions; - -#ifdef _WIN32 -#define _strcpy(dest, destSize, src) strcpy_s(dest, destSize, src) -#define snprintf sprintf_s -#else -#define _strcpy(dest, destSize, src) { strncpy(dest, src, destSize-1); (dest)[destSize-1] = '\0'; } -#endif - -#define PLUGIN_API_VERSION 23 - -#define PATH_BUFSIZE 512 -#define COMMAND_BUFSIZE 128 -#define INFODATA_BUFSIZE 128 -#define SERVERINFO_BUFSIZE 256 -#define CHANNELINFO_BUFSIZE 512 -#define RETURNCODE_BUFSIZE 128 - -static char* pluginID = NULL; - -#ifdef _WIN32 -/* Helper function to convert wchar_T to Utf-8 encoded strings on Windows */ -static int wcharToUtf8(const wchar_t* str, char** result) { - int outlen = WideCharToMultiByte(CP_UTF8, 0, str, -1, 0, 0, 0, 0); - *result = (char*)malloc(outlen); - if(WideCharToMultiByte(CP_UTF8, 0, str, -1, *result, outlen, 0, 0) == 0) { - *result = NULL; - return -1; - } - return 0; -} -#endif - -/*********************************** Required functions ************************************/ -/* - * If any of these required functions is not implemented, TS3 will refuse to load the plugin - */ - -/* Unique name identifying this plugin */ -const char* ts3plugin_name() { -#ifdef _WIN32 - /* TeamSpeak expects UTF-8 encoded characters. Following demonstrates a possibility how to convert UTF-16 wchar_t into UTF-8. */ - static char* result = NULL; /* Static variable so it's allocated only once */ - if(!result) { - const wchar_t* name = L"Test Plugin"; - if(wcharToUtf8(name, &result) == -1) { /* Convert name into UTF-8 encoded result */ - result = "Test Plugin"; /* Conversion failed, fallback here */ - } - } - return result; -#else - return "Test Plugin"; -#endif -} - -/* Plugin version */ -const char* ts3plugin_version() { - return "1.2"; -} - -/* Plugin API version. Must be the same as the clients API major version, else the plugin fails to load. */ -int ts3plugin_apiVersion() { - return PLUGIN_API_VERSION; -} - -/* Plugin author */ -const char* ts3plugin_author() { - /* If you want to use wchar_t, see ts3plugin_name() on how to use */ - return "TeamSpeak Systems GmbH"; -} - -/* Plugin description */ -const char* ts3plugin_description() { - /* If you want to use wchar_t, see ts3plugin_name() on how to use */ - return "This plugin demonstrates the TeamSpeak 3 client plugin architecture."; -} - -/* Set TeamSpeak 3 callback functions */ -void ts3plugin_setFunctionPointers(const struct TS3Functions funcs) { - ts3Functions = funcs; -} - -/* - * Custom code called right after loading the plugin. Returns 0 on success, 1 on failure. - * If the function returns 1 on failure, the plugin will be unloaded again. - */ -int ts3plugin_init() { - char appPath[PATH_BUFSIZE]; - char resourcesPath[PATH_BUFSIZE]; - char configPath[PATH_BUFSIZE]; - char pluginPath[PATH_BUFSIZE]; - - /* Your plugin init code here */ - printf("PLUGIN: init\n"); - - /* Example on how to query application, resources and configuration paths from client */ - /* Note: Console client returns empty string for app and resources path */ - ts3Functions.getAppPath(appPath, PATH_BUFSIZE); - ts3Functions.getResourcesPath(resourcesPath, PATH_BUFSIZE); - ts3Functions.getConfigPath(configPath, PATH_BUFSIZE); - ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE, pluginID); - - printf("PLUGIN: App path: %s\nResources path: %s\nConfig path: %s\nPlugin path: %s\n", appPath, resourcesPath, configPath, pluginPath); - - return 0; /* 0 = success, 1 = failure, -2 = failure but client will not show a "failed to load" warning */ - /* -2 is a very special case and should only be used if a plugin displays a dialog (e.g. overlay) asking the user to disable - * the plugin again, avoiding the show another dialog by the client telling the user the plugin failed to load. - * For normal case, if a plugin really failed to load because of an error, the correct return value is 1. */ -} - -/* Custom code called right before the plugin is unloaded */ -void ts3plugin_shutdown() { - /* Your plugin cleanup code here */ - printf("PLUGIN: shutdown\n"); - - /* - * Note: - * If your plugin implements a settings dialog, it must be closed and deleted here, else the - * TeamSpeak client will most likely crash (DLL removed but dialog from DLL code still open). - */ - - /* Free pluginID if we registered it */ - if(pluginID) { - free(pluginID); - pluginID = NULL; - } -} - -/****************************** Optional functions ********************************/ -/* - * Following functions are optional, if not needed you don't need to implement them. - */ - -/* Tell client if plugin offers a configuration window. If this function is not implemented, it's an assumed "does not offer" (PLUGIN_OFFERS_NO_CONFIGURE). */ -int ts3plugin_offersConfigure() { - printf("PLUGIN: offersConfigure\n"); - /* - * Return values: - * PLUGIN_OFFERS_NO_CONFIGURE - Plugin does not implement ts3plugin_configure - * PLUGIN_OFFERS_CONFIGURE_NEW_THREAD - Plugin does implement ts3plugin_configure and requests to run this function in an own thread - * PLUGIN_OFFERS_CONFIGURE_QT_THREAD - Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread - */ - return PLUGIN_OFFERS_NO_CONFIGURE; /* In this case ts3plugin_configure does not need to be implemented */ -} - -/* Plugin might offer a configuration window. If ts3plugin_offersConfigure returns 0, this function does not need to be implemented. */ -void ts3plugin_configure(void* handle, void* qParentWidget) { - printf("PLUGIN: configure\n"); -} - -/* - * If the plugin wants to use error return codes, plugin commands, hotkeys or menu items, it needs to register a command ID. This function will be - * automatically called after the plugin was initialized. This function is optional. If you don't use these features, this function can be omitted. - * Note the passed pluginID parameter is no longer valid after calling this function, so you must copy it and store it in the plugin. - */ -void ts3plugin_registerPluginID(const char* id) { - const size_t sz = strlen(id) + 1; - pluginID = (char*)malloc(sz * sizeof(char)); - _strcpy(pluginID, sz, id); /* The id buffer will invalidate after exiting this function */ - printf("PLUGIN: registerPluginID: %s\n", pluginID); -} - -/* Plugin command keyword. Return NULL or "" if not used. */ -const char* ts3plugin_commandKeyword() { - return "test"; -} - -static void print_and_free_bookmarks_list(struct PluginBookmarkList* list) -{ - int i; - for (i = 0; i < list->itemcount; ++i) { - if (list->items[i].isFolder) { - printf("Folder: name=%s\n", list->items[i].name); - print_and_free_bookmarks_list(list->items[i].folder); - ts3Functions.freeMemory(list->items[i].name); - } else { - printf("Bookmark: name=%s uuid=%s\n", list->items[i].name, list->items[i].uuid); - ts3Functions.freeMemory(list->items[i].name); - ts3Functions.freeMemory(list->items[i].uuid); - } - } - ts3Functions.freeMemory(list); -} - -/* Plugin processes console command. Return 0 if plugin handled the command, 1 if not handled. */ -int ts3plugin_processCommand(uint64 serverConnectionHandlerID, const char* command) { - char buf[COMMAND_BUFSIZE]; - char *s, *param1 = NULL, *param2 = NULL; - int i = 0; - enum { CMD_NONE = 0, CMD_JOIN, CMD_COMMAND, CMD_SERVERINFO, CMD_CHANNELINFO, CMD_AVATAR, CMD_ENABLEMENU, CMD_SUBSCRIBE, CMD_UNSUBSCRIBE, CMD_SUBSCRIBEALL, CMD_UNSUBSCRIBEALL, CMD_BOOKMARKSLIST } cmd = CMD_NONE; -#ifdef _WIN32 - char* context = NULL; -#endif - - printf("PLUGIN: process command: '%s'\n", command); - - _strcpy(buf, COMMAND_BUFSIZE, command); -#ifdef _WIN32 - s = strtok_s(buf, " ", &context); -#else - s = strtok(buf, " "); -#endif - while(s != NULL) { - if(i == 0) { - if(!strcmp(s, "join")) { - cmd = CMD_JOIN; - } else if(!strcmp(s, "command")) { - cmd = CMD_COMMAND; - } else if(!strcmp(s, "serverinfo")) { - cmd = CMD_SERVERINFO; - } else if(!strcmp(s, "channelinfo")) { - cmd = CMD_CHANNELINFO; - } else if(!strcmp(s, "avatar")) { - cmd = CMD_AVATAR; - } else if(!strcmp(s, "enablemenu")) { - cmd = CMD_ENABLEMENU; - } else if(!strcmp(s, "subscribe")) { - cmd = CMD_SUBSCRIBE; - } else if(!strcmp(s, "unsubscribe")) { - cmd = CMD_UNSUBSCRIBE; - } else if(!strcmp(s, "subscribeall")) { - cmd = CMD_SUBSCRIBEALL; - } else if(!strcmp(s, "unsubscribeall")) { - cmd = CMD_UNSUBSCRIBEALL; - } else if (!strcmp(s, "bookmarkslist")) { - cmd = CMD_BOOKMARKSLIST; - } - } else if(i == 1) { - param1 = s; - } else { - param2 = s; - } -#ifdef _WIN32 - s = strtok_s(NULL, " ", &context); -#else - s = strtok(NULL, " "); -#endif - i++; - } - - switch(cmd) { - case CMD_NONE: - return 1; /* Command not handled by plugin */ - case CMD_JOIN: /* /test join [optionalCannelPassword] */ - if(param1) { - uint64 channelID = (uint64)atoi(param1); - char* password = param2 ? param2 : ""; - char returnCode[RETURNCODE_BUFSIZE]; - anyID myID; - - /* Get own clientID */ - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { - ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - break; - } - - /* Create return code for requestClientMove function call. If creation fails, returnCode will be NULL, which can be - * passed into the client functions meaning no return code is used. - * Note: To use return codes, the plugin needs to register a plugin ID using ts3plugin_registerPluginID */ - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - - /* In a real world plugin, the returnCode should be remembered (e.g. in a dynamic STL vector, if it's a C++ plugin). - * onServerErrorEvent can then check the received returnCode, compare with the remembered ones and thus identify - * which function call has triggered the event and react accordingly. */ - - /* Request joining specified channel using above created return code */ - if(ts3Functions.requestClientMove(serverConnectionHandlerID, myID, channelID, password, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error requesting client move", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - } else { - ts3Functions.printMessageToCurrentTab("Missing channel ID parameter."); - } - break; - case CMD_COMMAND: /* /test command */ - if(param1) { - /* Send plugin command to all clients in current channel. In this case targetIds is unused and can be NULL. */ - if(pluginID) { - /* See ts3plugin_registerPluginID for how to obtain a pluginID */ - printf("PLUGIN: Sending plugin command to current channel: %s\n", param1); - ts3Functions.sendPluginCommand(serverConnectionHandlerID, pluginID, param1, PluginCommandTarget_CURRENT_CHANNEL, NULL, NULL); - } else { - printf("PLUGIN: Failed to send plugin command, was not registered.\n"); - } - } else { - ts3Functions.printMessageToCurrentTab("Missing command parameter."); - } - break; - case CMD_SERVERINFO: { /* /test serverinfo */ - /* Query host, port and server password of current server tab. - * The password parameter can be NULL if the plugin does not want to receive the server password. - * Note: Server password is only available if the user has actually used it when connecting. If a user has - * connected with the permission to ignore passwords (b_virtualserver_join_ignore_password) and the password, - * was not entered, it will not be available. - * getServerConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */ - char host[SERVERINFO_BUFSIZE]; - /*char password[SERVERINFO_BUFSIZE];*/ - char* password = NULL; /* Don't receive server password */ - unsigned short port; - if(!ts3Functions.getServerConnectInfo(serverConnectionHandlerID, host, &port, password, SERVERINFO_BUFSIZE)) { - char msg[SERVERINFO_BUFSIZE]; - snprintf(msg, sizeof(msg), "Server Connect Info: %s:%d", host, port); - ts3Functions.printMessageToCurrentTab(msg); - } else { - ts3Functions.printMessageToCurrentTab("No server connect info available."); - } - break; - } - case CMD_CHANNELINFO: { /* /test channelinfo */ - /* Query channel path and password of current server tab. - * The password parameter can be NULL if the plugin does not want to receive the channel password. - * Note: Channel password is only available if the user has actually used it when entering the channel. If a user has - * entered a channel with the permission to ignore passwords (b_channel_join_ignore_password) and the password, - * was not entered, it will not be available. - * getChannelConnectInfo returns 0 on success, 1 on error or if current server tab is disconnected. */ - char path[CHANNELINFO_BUFSIZE]; - /*char password[CHANNELINFO_BUFSIZE];*/ - char* password = NULL; /* Don't receive channel password */ - - /* Get own clientID and channelID */ - anyID myID; - uint64 myChannelID; - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { - ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - break; - } - /* Get own channel ID */ - if(ts3Functions.getChannelOfClient(serverConnectionHandlerID, myID, &myChannelID) != ERROR_ok) { - ts3Functions.logMessage("Error querying channel ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - break; - } - - /* Get channel connect info of own channel */ - if(!ts3Functions.getChannelConnectInfo(serverConnectionHandlerID, myChannelID, path, password, CHANNELINFO_BUFSIZE)) { - char msg[CHANNELINFO_BUFSIZE]; - snprintf(msg, sizeof(msg), "Channel Connect Info: %s", path); - ts3Functions.printMessageToCurrentTab(msg); - } else { - ts3Functions.printMessageToCurrentTab("No channel connect info available."); - } - break; - } - case CMD_AVATAR: { /* /test avatar */ - char avatarPath[PATH_BUFSIZE]; - anyID clientID = (anyID)atoi(param1); - unsigned int error; - - memset(avatarPath, 0, PATH_BUFSIZE); - error = ts3Functions.getAvatar(serverConnectionHandlerID, clientID, avatarPath, PATH_BUFSIZE); - if(error == ERROR_ok) { /* ERROR_ok means the client has an avatar set. */ - if(strlen(avatarPath)) { /* Avatar path contains the full path to the avatar image in the TS3Client cache directory */ - printf("Avatar path: %s\n", avatarPath); - } else { /* Empty avatar path means the client has an avatar but the image has not yet been cached. The TeamSpeak - * client will automatically start the download and call onAvatarUpdated when done */ - printf("Avatar not yet downloaded, waiting for onAvatarUpdated...\n"); - } - } else if(error == ERROR_database_empty_result) { /* Not an error, the client simply has no avatar set */ - printf("Client has no avatar\n"); - } else { /* Other error occured (invalid server connection handler ID, invalid client ID, file io error etc) */ - printf("Error getting avatar: %d\n", error); - } - break; - } - case CMD_ENABLEMENU: /* /test enablemenu <0|1> */ - if(param1) { - int menuID = atoi(param1); - int enable = param2 ? atoi(param2) : 0; - ts3Functions.setPluginMenuEnabled(pluginID, menuID, enable); - } else { - ts3Functions.printMessageToCurrentTab("Usage is: /test enablemenu <0|1>"); - } - break; - case CMD_SUBSCRIBE: /* /test subscribe */ - if(param1) { - char returnCode[RETURNCODE_BUFSIZE]; - uint64 channelIDArray[2]; - channelIDArray[0] = (uint64)atoi(param1); - channelIDArray[1] = 0; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelSubscribe(serverConnectionHandlerID, channelIDArray, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - } - break; - case CMD_UNSUBSCRIBE: /* /test unsubscribe */ - if(param1) { - char returnCode[RETURNCODE_BUFSIZE]; - uint64 channelIDArray[2]; - channelIDArray[0] = (uint64)atoi(param1); - channelIDArray[1] = 0; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelUnsubscribe(serverConnectionHandlerID, channelIDArray, NULL) != ERROR_ok) { - ts3Functions.logMessage("Error unsubscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - } - break; - case CMD_SUBSCRIBEALL: { /* /test subscribeall */ - char returnCode[RETURNCODE_BUFSIZE]; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelSubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - break; - } - case CMD_UNSUBSCRIBEALL: { /* /test unsubscribeall */ - char returnCode[RETURNCODE_BUFSIZE]; - ts3Functions.createReturnCode(pluginID, returnCode, RETURNCODE_BUFSIZE); - if(ts3Functions.requestChannelUnsubscribeAll(serverConnectionHandlerID, returnCode) != ERROR_ok) { - ts3Functions.logMessage("Error subscribing channel", LogLevel_INFO, "Plugin", serverConnectionHandlerID); - } - break; - } - case CMD_BOOKMARKSLIST: { /* test bookmarkslist */ - struct PluginBookmarkList* list; - unsigned int error = ts3Functions.getBookmarkList(&list); - if (error == ERROR_ok) { - print_and_free_bookmarks_list(list); - } - else { - ts3Functions.logMessage("Error getting bookmarks list", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } - break; - } - } - - return 0; /* Plugin handled command */ -} - -/* Client changed current server connection handler */ -void ts3plugin_currentServerConnectionChanged(uint64 serverConnectionHandlerID) { - printf("PLUGIN: currentServerConnectionChanged %llu (%llu)\n", (long long unsigned int)serverConnectionHandlerID, (long long unsigned int)ts3Functions.getCurrentServerConnectionHandlerID()); -} - -/* - * Implement the following three functions when the plugin should display a line in the server/channel/client info. - * If any of ts3plugin_infoTitle, ts3plugin_infoData or ts3plugin_freeMemory is missing, the info text will not be displayed. - */ - -/* Static title shown in the left column in the info frame */ -const char* ts3plugin_infoTitle() { - return "Test plugin info"; -} - -/* - * Dynamic content shown in the right column in the info frame. Memory for the data string needs to be allocated in this - * function. The client will call ts3plugin_freeMemory once done with the string to release the allocated memory again. - * Check the parameter "type" if you want to implement this feature only for specific item types. Set the parameter - * "data" to NULL to have the client ignore the info data. - */ -void ts3plugin_infoData(uint64 serverConnectionHandlerID, uint64 id, enum PluginItemType type, char** data) { - char* name; - - /* For demonstration purpose, display the name of the currently selected server, channel or client. */ - switch(type) { - case PLUGIN_SERVER: - if(ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_NAME, &name) != ERROR_ok) { - printf("Error getting virtual server name\n"); - return; - } - break; - case PLUGIN_CHANNEL: - if(ts3Functions.getChannelVariableAsString(serverConnectionHandlerID, id, CHANNEL_NAME, &name) != ERROR_ok) { - printf("Error getting channel name\n"); - return; - } - break; - case PLUGIN_CLIENT: - if(ts3Functions.getClientVariableAsString(serverConnectionHandlerID, (anyID)id, CLIENT_NICKNAME, &name) != ERROR_ok) { - printf("Error getting client nickname\n"); - return; - } - break; - default: - printf("Invalid item type: %d\n", type); - data = NULL; /* Ignore */ - return; - } - - *data = (char*)malloc(INFODATA_BUFSIZE * sizeof(char)); /* Must be allocated in the plugin! */ - snprintf(*data, INFODATA_BUFSIZE, "The nickname is [I]\"%s\"[/I]", name); /* bbCode is supported. HTML is not supported */ - ts3Functions.freeMemory(name); -} - -/* Required to release the memory for parameter "data" allocated in ts3plugin_infoData and ts3plugin_initMenus */ -void ts3plugin_freeMemory(void* data) { - free(data); -} - -/* - * Plugin requests to be always automatically loaded by the TeamSpeak 3 client unless - * the user manually disabled it in the plugin dialog. - * This function is optional. If missing, no autoload is assumed. - */ -int ts3plugin_requestAutoload() { - return 0; /* 1 = request autoloaded, 0 = do not request autoload */ -} - -/* Helper function to create a menu item */ -static struct PluginMenuItem* createMenuItem(enum PluginMenuType type, int id, const char* text, const char* icon) { - struct PluginMenuItem* menuItem = (struct PluginMenuItem*)malloc(sizeof(struct PluginMenuItem)); - menuItem->type = type; - menuItem->id = id; - _strcpy(menuItem->text, PLUGIN_MENU_BUFSZ, text); - _strcpy(menuItem->icon, PLUGIN_MENU_BUFSZ, icon); - return menuItem; -} - -/* Some makros to make the code to create menu items a bit more readable */ -#define BEGIN_CREATE_MENUS(x) const size_t sz = x + 1; size_t n = 0; *menuItems = (struct PluginMenuItem**)malloc(sizeof(struct PluginMenuItem*) * sz); -#define CREATE_MENU_ITEM(a, b, c, d) (*menuItems)[n++] = createMenuItem(a, b, c, d); -#define END_CREATE_MENUS (*menuItems)[n++] = NULL; assert(n == sz); - -/* - * Menu IDs for this plugin. Pass these IDs when creating a menuitem to the TS3 client. When the menu item is triggered, - * ts3plugin_onMenuItemEvent will be called passing the menu ID of the triggered menu item. - * These IDs are freely choosable by the plugin author. It's not really needed to use an enum, it just looks prettier. - */ -enum { - MENU_ID_CLIENT_1 = 1, - MENU_ID_CLIENT_2, - MENU_ID_CHANNEL_1, - MENU_ID_CHANNEL_2, - MENU_ID_CHANNEL_3, - MENU_ID_GLOBAL_1, - MENU_ID_GLOBAL_2 -}; - -/* - * Initialize plugin menus. - * This function is called after ts3plugin_init and ts3plugin_registerPluginID. A pluginID is required for plugin menus to work. - * Both ts3plugin_registerPluginID and ts3plugin_freeMemory must be implemented to use menus. - * If plugin menus are not used by a plugin, do not implement this function or return NULL. - */ -void ts3plugin_initMenus(struct PluginMenuItem*** menuItems, char** menuIcon) { - /* - * Create the menus - * There are three types of menu items: - * - PLUGIN_MENU_TYPE_CLIENT: Client context menu - * - PLUGIN_MENU_TYPE_CHANNEL: Channel context menu - * - PLUGIN_MENU_TYPE_GLOBAL: "Plugins" menu in menu bar of main window - * - * Menu IDs are used to identify the menu item when ts3plugin_onMenuItemEvent is called - * - * The menu text is required, max length is 128 characters - * - * The icon is optional, max length is 128 characters. When not using icons, just pass an empty string. - * Icons are loaded from a subdirectory in the TeamSpeak client plugins folder. The subdirectory must be named like the - * plugin filename, without dll/so/dylib suffix - * e.g. for "test_plugin.dll", icon "1.png" is loaded from \plugins\test_plugin\1.png - */ - - BEGIN_CREATE_MENUS(7); /* IMPORTANT: Number of menu items must be correct! */ - CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT, MENU_ID_CLIENT_1, "Client item 1", "1.png"); - CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CLIENT, MENU_ID_CLIENT_2, "Client item 2", "2.png"); - CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_1, "Channel item 1", "1.png"); - CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_2, "Channel item 2", "2.png"); - CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_CHANNEL, MENU_ID_CHANNEL_3, "Channel item 3", "3.png"); - CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL, MENU_ID_GLOBAL_1, "Global item 1", "1.png"); - CREATE_MENU_ITEM(PLUGIN_MENU_TYPE_GLOBAL, MENU_ID_GLOBAL_2, "Global item 2", "2.png"); - END_CREATE_MENUS; /* Includes an assert checking if the number of menu items matched */ - - /* - * Specify an optional icon for the plugin. This icon is used for the plugins submenu within context and main menus - * If unused, set menuIcon to NULL - */ - *menuIcon = (char*)malloc(PLUGIN_MENU_BUFSZ * sizeof(char)); - _strcpy(*menuIcon, PLUGIN_MENU_BUFSZ, "t.png"); - - /* - * Menus can be enabled or disabled with: ts3Functions.setPluginMenuEnabled(pluginID, menuID, 0|1); - * Test it with plugin command: /test enablemenu <0|1> - * Menus are enabled by default. Please note that shown menus will not automatically enable or disable when calling this function to - * ensure Qt menus are not modified by any thread other the UI thread. The enabled or disable state will change the next time a - * menu is displayed. - */ - /* For example, this would disable MENU_ID_GLOBAL_2: */ - /* ts3Functions.setPluginMenuEnabled(pluginID, MENU_ID_GLOBAL_2, 0); */ - - /* All memory allocated in this function will be automatically released by the TeamSpeak client later by calling ts3plugin_freeMemory */ -} - -/* Helper function to create a hotkey */ -static struct PluginHotkey* createHotkey(const char* keyword, const char* description) { - struct PluginHotkey* hotkey = (struct PluginHotkey*)malloc(sizeof(struct PluginHotkey)); - _strcpy(hotkey->keyword, PLUGIN_HOTKEY_BUFSZ, keyword); - _strcpy(hotkey->description, PLUGIN_HOTKEY_BUFSZ, description); - return hotkey; -} - -/* Some makros to make the code to create hotkeys a bit more readable */ -#define BEGIN_CREATE_HOTKEYS(x) const size_t sz = x + 1; size_t n = 0; *hotkeys = (struct PluginHotkey**)malloc(sizeof(struct PluginHotkey*) * sz); -#define CREATE_HOTKEY(a, b) (*hotkeys)[n++] = createHotkey(a, b); -#define END_CREATE_HOTKEYS (*hotkeys)[n++] = NULL; assert(n == sz); - -/* - * Initialize plugin hotkeys. If your plugin does not use this feature, this function can be omitted. - * Hotkeys require ts3plugin_registerPluginID and ts3plugin_freeMemory to be implemented. - * This function is automatically called by the client after ts3plugin_init. - */ -void ts3plugin_initHotkeys(struct PluginHotkey*** hotkeys) { - /* Register hotkeys giving a keyword and a description. - * The keyword will be later passed to ts3plugin_onHotkeyEvent to identify which hotkey was triggered. - * The description is shown in the clients hotkey dialog. */ - BEGIN_CREATE_HOTKEYS(3); /* Create 3 hotkeys. Size must be correct for allocating memory. */ - CREATE_HOTKEY("keyword_1", "Test hotkey 1"); - CREATE_HOTKEY("keyword_2", "Test hotkey 2"); - CREATE_HOTKEY("keyword_3", "Test hotkey 3"); - END_CREATE_HOTKEYS; - - /* The client will call ts3plugin_freeMemory to release all allocated memory */ -} - -/************************** TeamSpeak callbacks ***************************/ -/* - * Following functions are optional, feel free to remove unused callbacks. - * See the clientlib documentation for details on each function. - */ - -/* Clientlib */ - -void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int newStatus, unsigned int errorNumber) { - /* Some example code following to show how to use the information query functions. */ - - if(newStatus == STATUS_CONNECTION_ESTABLISHED) { /* connection established and we have client and channels available */ - char* s; - char msg[1024]; - anyID myID; - uint64* ids; - size_t i; - unsigned int error; - - /* Print clientlib version */ - if(ts3Functions.getClientLibVersion(&s) == ERROR_ok) { - printf("PLUGIN: Client lib version: %s\n", s); - ts3Functions.freeMemory(s); /* Release string */ - } else { - ts3Functions.logMessage("Error querying client lib version", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return; - } - - /* Write plugin name and version to log */ - snprintf(msg, sizeof(msg), "Plugin %s, Version %s, Author: %s", ts3plugin_name(), ts3plugin_version(), ts3plugin_author()); - ts3Functions.logMessage(msg, LogLevel_INFO, "Plugin", serverConnectionHandlerID); - - /* Print virtual server name */ - if((error = ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_NAME, &s)) != ERROR_ok) { - if(error != ERROR_not_connected) { /* Don't spam error in this case (failed to connect) */ - ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } - return; - } - printf("PLUGIN: Server name: %s\n", s); - ts3Functions.freeMemory(s); - - /* Print virtual server welcome message */ - if(ts3Functions.getServerVariableAsString(serverConnectionHandlerID, VIRTUALSERVER_WELCOMEMESSAGE, &s) != ERROR_ok) { - ts3Functions.logMessage("Error querying server welcome message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return; - } - printf("PLUGIN: Server welcome message: %s\n", s); - ts3Functions.freeMemory(s); /* Release string */ - - /* Print own client ID and nickname on this server */ - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { - ts3Functions.logMessage("Error querying client ID", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return; - } - if(ts3Functions.getClientSelfVariableAsString(serverConnectionHandlerID, CLIENT_NICKNAME, &s) != ERROR_ok) { - ts3Functions.logMessage("Error querying client nickname", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return; - } - printf("PLUGIN: My client ID = %d, nickname = %s\n", myID, s); - ts3Functions.freeMemory(s); - - /* Print list of all channels on this server */ - if(ts3Functions.getChannelList(serverConnectionHandlerID, &ids) != ERROR_ok) { - ts3Functions.logMessage("Error getting channel list", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return; - } - printf("PLUGIN: Available channels:\n"); - for(i=0; ids[i]; i++) { - /* Query channel name */ - if(ts3Functions.getChannelVariableAsString(serverConnectionHandlerID, ids[i], CHANNEL_NAME, &s) != ERROR_ok) { - ts3Functions.logMessage("Error querying channel name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return; - } - printf("PLUGIN: Channel ID = %llu, name = %s\n", (long long unsigned int)ids[i], s); - ts3Functions.freeMemory(s); - } - ts3Functions.freeMemory(ids); /* Release array */ - - /* Print list of existing server connection handlers */ - printf("PLUGIN: Existing server connection handlers:\n"); - if(ts3Functions.getServerConnectionHandlerList(&ids) != ERROR_ok) { - ts3Functions.logMessage("Error getting server list", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return; - } - for(i=0; ids[i]; i++) { - if((error = ts3Functions.getServerVariableAsString(ids[i], VIRTUALSERVER_NAME, &s)) != ERROR_ok) { - if(error != ERROR_not_connected) { /* Don't spam error in this case (failed to connect) */ - ts3Functions.logMessage("Error querying server name", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } - continue; - } - printf("- %llu - %s\n", (long long unsigned int)ids[i], s); - ts3Functions.freeMemory(s); - } - ts3Functions.freeMemory(ids); - } -} - -void ts3plugin_onNewChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID) { -} - -void ts3plugin_onNewChannelCreatedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) { -} - -void ts3plugin_onDelChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) { -} - -void ts3plugin_onChannelMoveEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 newChannelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) { -} - -void ts3plugin_onUpdateChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID) { -} - -void ts3plugin_onUpdateChannelEditedEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) { -} - -void ts3plugin_onUpdateClientEvent(uint64 serverConnectionHandlerID, anyID clientID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) { -} - -void ts3plugin_onClientMoveEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* moveMessage) { -} - -void ts3plugin_onClientMoveSubscriptionEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility) { -} - -void ts3plugin_onClientMoveTimeoutEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* timeoutMessage) { -} - -void ts3plugin_onClientMoveMovedEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID moverID, const char* moverName, const char* moverUniqueIdentifier, const char* moveMessage) { -} - -void ts3plugin_onClientKickFromChannelEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage) { -} - -void ts3plugin_onClientKickFromServerEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage) { -} - -void ts3plugin_onClientIDsEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, anyID clientID, const char* clientName) { -} - -void ts3plugin_onClientIDsFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onServerEditedEvent(uint64 serverConnectionHandlerID, anyID editerID, const char* editerName, const char* editerUniqueIdentifier) { -} - -void ts3plugin_onServerUpdatedEvent(uint64 serverConnectionHandlerID) { -} - -int ts3plugin_onServerErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage) { - printf("PLUGIN: onServerErrorEvent %llu %s %d %s\n", (long long unsigned int)serverConnectionHandlerID, errorMessage, error, (returnCode ? returnCode : "")); - if(returnCode) { - /* A plugin could now check the returnCode with previously (when calling a function) remembered returnCodes and react accordingly */ - /* In case of using a a plugin return code, the plugin can return: - * 0: Client will continue handling this error (print to chat tab) - * 1: Client will ignore this error, the plugin announces it has handled it */ - return 1; - } - return 0; /* If no plugin return code was used, the return value of this function is ignored */ -} - -void ts3plugin_onServerStopEvent(uint64 serverConnectionHandlerID, const char* shutdownMessage) { -} - -int ts3plugin_onTextMessageEvent(uint64 serverConnectionHandlerID, anyID targetMode, anyID toID, anyID fromID, const char* fromName, const char* fromUniqueIdentifier, const char* message, int ffIgnored) { - printf("PLUGIN: onTextMessageEvent %llu %d %d %s %s %d\n", (long long unsigned int)serverConnectionHandlerID, targetMode, fromID, fromName, message, ffIgnored); - - /* Friend/Foe manager has ignored the message, so ignore here as well. */ - if(ffIgnored) { - return 0; /* Client will ignore the message anyways, so return value here doesn't matter */ - } - -#if 0 - { - /* Example code: Autoreply to sender */ - /* Disabled because quite annoying, but should give you some ideas what is possible here */ - /* Careful, when two clients use this, they will get banned quickly... */ - anyID myID; - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { - ts3Functions.logMessage("Error querying own client id", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return 0; - } - if(fromID != myID) { /* Don't reply when source is own client */ - if(ts3Functions.requestSendPrivateTextMsg(serverConnectionHandlerID, "Text message back!", fromID, NULL) != ERROR_ok) { - ts3Functions.logMessage("Error requesting send text message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } - } - } -#endif - - return 0; /* 0 = handle normally, 1 = client will ignore the text message */ -} - -void ts3plugin_onTalkStatusChangeEvent(uint64 serverConnectionHandlerID, int status, int isReceivedWhisper, anyID clientID) { - /* Demonstrate usage of getClientDisplayName */ - char name[512]; - if(ts3Functions.getClientDisplayName(serverConnectionHandlerID, clientID, name, 512) == ERROR_ok) { - if(status == STATUS_TALKING) { - printf("--> %s starts talking\n", name); - } else { - printf("--> %s stops talking\n", name); - } - } -} - -void ts3plugin_onConnectionInfoEvent(uint64 serverConnectionHandlerID, anyID clientID) { -} - -void ts3plugin_onServerConnectionInfoEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onChannelSubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID) { -} - -void ts3plugin_onChannelSubscribeFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onChannelUnsubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID) { -} - -void ts3plugin_onChannelUnsubscribeFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onChannelDescriptionUpdateEvent(uint64 serverConnectionHandlerID, uint64 channelID) { -} - -void ts3plugin_onChannelPasswordChangedEvent(uint64 serverConnectionHandlerID, uint64 channelID) { -} - -void ts3plugin_onPlaybackShutdownCompleteEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onSoundDeviceListChangedEvent(const char* modeID, int playOrCap) { -} - -void ts3plugin_onEditPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels) { -} - -void ts3plugin_onEditPostProcessVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask) { -} - -void ts3plugin_onEditMixedPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask) { -} - -void ts3plugin_onEditCapturedVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, int* edited) { -} - -void ts3plugin_onCustom3dRolloffCalculationClientEvent(uint64 serverConnectionHandlerID, anyID clientID, float distance, float* volume) { -} - -void ts3plugin_onCustom3dRolloffCalculationWaveEvent(uint64 serverConnectionHandlerID, uint64 waveHandle, float distance, float* volume) { -} - -void ts3plugin_onUserLoggingMessageEvent(const char* logMessage, int logLevel, const char* logChannel, uint64 logID, const char* logTime, const char* completeLogString) { -} - -/* Clientlib rare */ - -void ts3plugin_onClientBanFromServerEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, uint64 time, const char* kickMessage) { -} - -int ts3plugin_onClientPokeEvent(uint64 serverConnectionHandlerID, anyID fromClientID, const char* pokerName, const char* pokerUniqueIdentity, const char* message, int ffIgnored) { - anyID myID; - - printf("PLUGIN onClientPokeEvent: %llu %d %s %s %d\n", (long long unsigned int)serverConnectionHandlerID, fromClientID, pokerName, message, ffIgnored); - - /* Check if the Friend/Foe manager has already blocked this poke */ - if(ffIgnored) { - return 0; /* Client will block anyways, doesn't matter what we return */ - } - - /* Example code: Send text message back to poking client */ - if(ts3Functions.getClientID(serverConnectionHandlerID, &myID) != ERROR_ok) { /* Get own client ID */ - ts3Functions.logMessage("Error querying own client id", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - return 0; - } - if(fromClientID != myID) { /* Don't reply when source is own client */ - if(ts3Functions.requestSendPrivateTextMsg(serverConnectionHandlerID, "Received your poke!", fromClientID, NULL) != ERROR_ok) { - ts3Functions.logMessage("Error requesting send text message", LogLevel_ERROR, "Plugin", serverConnectionHandlerID); - } - } - - return 0; /* 0 = handle normally, 1 = client will ignore the poke */ -} - -void ts3plugin_onClientSelfVariableUpdateEvent(uint64 serverConnectionHandlerID, int flag, const char* oldValue, const char* newValue) { -} - -void ts3plugin_onFileListEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path, const char* name, uint64 size, uint64 datetime, int type, uint64 incompletesize, const char* returnCode) { -} - -void ts3plugin_onFileListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path) { -} - -void ts3plugin_onFileInfoEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* name, uint64 size, uint64 datetime) { -} - -void ts3plugin_onServerGroupListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, const char* name, int type, int iconID, int saveDB) { -} - -void ts3plugin_onServerGroupListFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onServerGroupByClientIDEvent(uint64 serverConnectionHandlerID, const char* name, uint64 serverGroupList, uint64 clientDatabaseID) { -} - -void ts3plugin_onServerGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) { -} - -void ts3plugin_onServerGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID) { -} - -void ts3plugin_onServerGroupClientListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, uint64 clientDatabaseID, const char* clientNameIdentifier, const char* clientUniqueID) { -} - -void ts3plugin_onChannelGroupListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, const char* name, int type, int iconID, int saveDB) { -} - -void ts3plugin_onChannelGroupListFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onChannelGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) { -} - -void ts3plugin_onChannelGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID) { -} - -void ts3plugin_onChannelPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) { -} - -void ts3plugin_onChannelPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID) { -} - -void ts3plugin_onClientPermListEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) { -} - -void ts3plugin_onClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID) { -} - -void ts3plugin_onChannelClientPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) { -} - -void ts3plugin_onChannelClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID) { -} - -void ts3plugin_onClientChannelGroupChangedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, uint64 channelID, anyID clientID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) { -} - -int ts3plugin_onServerPermissionErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, unsigned int failedPermissionID) { - return 0; /* See onServerErrorEvent for return code description */ -} - -void ts3plugin_onPermissionListGroupEndIDEvent(uint64 serverConnectionHandlerID, unsigned int groupEndID) { -} - -void ts3plugin_onPermissionListEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, const char* permissionName, const char* permissionDescription) { -} - -void ts3plugin_onPermissionListFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onPermissionOverviewEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, uint64 channelID, int overviewType, uint64 overviewID1, uint64 overviewID2, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip) { -} - -void ts3plugin_onPermissionOverviewFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onServerGroupClientAddedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) { -} - -void ts3plugin_onServerGroupClientDeletedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) { -} - -void ts3plugin_onClientNeededPermissionsEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, int permissionValue) { -} - -void ts3plugin_onClientNeededPermissionsFinishedEvent(uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onFileTransferStatusEvent(anyID transferID, unsigned int status, const char* statusMessage, uint64 remotefileSize, uint64 serverConnectionHandlerID) { -} - -void ts3plugin_onClientChatClosedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity) { -} - -void ts3plugin_onClientChatComposingEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity) { -} - -void ts3plugin_onServerLogEvent(uint64 serverConnectionHandlerID, const char* logMsg) { -} - -void ts3plugin_onServerLogFinishedEvent(uint64 serverConnectionHandlerID, uint64 lastPos, uint64 fileSize) { -} - -void ts3plugin_onMessageListEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, uint64 timestamp, int flagRead) { -} - -void ts3plugin_onMessageGetEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, const char* message, uint64 timestamp) { -} - -void ts3plugin_onClientDBIDfromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID) { -} - -void ts3plugin_onClientNamefromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName) { -} - -void ts3plugin_onClientNamefromDBIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName) { -} - -void ts3plugin_onComplainListEvent(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, const char* targetClientNickName, uint64 fromClientDatabaseID, const char* fromClientNickName, const char* complainReason, uint64 timestamp) { -} - -void ts3plugin_onBanListEvent(uint64 serverConnectionHandlerID, uint64 banid, const char* ip, const char* name, const char* uid, const char* mytsid, uint64 creationTime, uint64 durationTime, const char* invokerName, - uint64 invokercldbid, const char* invokeruid, const char* reason, int numberOfEnforcements, const char* lastNickName) { -} - -void ts3plugin_onClientServerQueryLoginPasswordEvent(uint64 serverConnectionHandlerID, const char* loginPassword) { -} - -void ts3plugin_onPluginCommandEvent(uint64 serverConnectionHandlerID, const char* pluginName, const char* pluginCommand, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity) { - printf("ON PLUGIN COMMAND: %s %s %d %s %s\n", pluginName, pluginCommand, invokerClientID, invokerName, invokerUniqueIdentity); -} - -void ts3plugin_onIncomingClientQueryEvent(uint64 serverConnectionHandlerID, const char* commandText) { -} - -void ts3plugin_onServerTemporaryPasswordListEvent(uint64 serverConnectionHandlerID, const char* clientNickname, const char* uniqueClientIdentifier, const char* description, const char* password, uint64 timestampStart, uint64 timestampEnd, uint64 targetChannelID, const char* targetChannelPW) { -} - -/* Client UI callbacks */ - -/* - * Called from client when an avatar image has been downloaded to or deleted from cache. - * This callback can be called spontaneously or in response to ts3Functions.getAvatar() - */ -void ts3plugin_onAvatarUpdated(uint64 serverConnectionHandlerID, anyID clientID, const char* avatarPath) { - /* If avatarPath is NULL, the avatar got deleted */ - /* If not NULL, avatarPath contains the path to the avatar file in the TS3Client cache */ - if(avatarPath != NULL) { - printf("onAvatarUpdated: %llu %d %s\n", (long long unsigned int)serverConnectionHandlerID, clientID, avatarPath); - } else { - printf("onAvatarUpdated: %llu %d - deleted\n", (long long unsigned int)serverConnectionHandlerID, clientID); - } -} - -/* - * Called when a plugin menu item (see ts3plugin_initMenus) is triggered. Optional function, when not using plugin menus, do not implement this. - * - * Parameters: - * - serverConnectionHandlerID: ID of the current server tab - * - type: Type of the menu (PLUGIN_MENU_TYPE_CHANNEL, PLUGIN_MENU_TYPE_CLIENT or PLUGIN_MENU_TYPE_GLOBAL) - * - menuItemID: Id used when creating the menu item - * - selectedItemID: Channel or Client ID in the case of PLUGIN_MENU_TYPE_CHANNEL and PLUGIN_MENU_TYPE_CLIENT. 0 for PLUGIN_MENU_TYPE_GLOBAL. - */ -void ts3plugin_onMenuItemEvent(uint64 serverConnectionHandlerID, enum PluginMenuType type, int menuItemID, uint64 selectedItemID) { - printf("PLUGIN: onMenuItemEvent: serverConnectionHandlerID=%llu, type=%d, menuItemID=%d, selectedItemID=%llu\n", (long long unsigned int)serverConnectionHandlerID, type, menuItemID, (long long unsigned int)selectedItemID); - switch(type) { - case PLUGIN_MENU_TYPE_GLOBAL: - /* Global menu item was triggered. selectedItemID is unused and set to zero. */ - switch(menuItemID) { - case MENU_ID_GLOBAL_1: - /* Menu global 1 was triggered */ - break; - case MENU_ID_GLOBAL_2: - /* Menu global 2 was triggered */ - break; - default: - break; - } - break; - case PLUGIN_MENU_TYPE_CHANNEL: - /* Channel contextmenu item was triggered. selectedItemID is the channelID of the selected channel */ - switch(menuItemID) { - case MENU_ID_CHANNEL_1: - /* Menu channel 1 was triggered */ - break; - case MENU_ID_CHANNEL_2: - /* Menu channel 2 was triggered */ - break; - case MENU_ID_CHANNEL_3: - /* Menu channel 3 was triggered */ - break; - default: - break; - } - break; - case PLUGIN_MENU_TYPE_CLIENT: - /* Client contextmenu item was triggered. selectedItemID is the clientID of the selected client */ - switch(menuItemID) { - case MENU_ID_CLIENT_1: - /* Menu client 1 was triggered */ - break; - case MENU_ID_CLIENT_2: - /* Menu client 2 was triggered */ - break; - default: - break; - } - break; - default: - break; - } -} - -/* This function is called if a plugin hotkey was pressed. Omit if hotkeys are unused. */ -void ts3plugin_onHotkeyEvent(const char* keyword) { - printf("PLUGIN: Hotkey event: %s\n", keyword); - /* Identify the hotkey by keyword ("keyword_1", "keyword_2" or "keyword_3" in this example) and handle here... */ -} - -/* Called when recording a hotkey has finished after calling ts3Functions.requestHotkeyInputDialog */ -void ts3plugin_onHotkeyRecordedEvent(const char* keyword, const char* key) { -} - -// This function receives your key Identifier you send to notifyKeyEvent and should return -// the friendly device name of the device this hotkey originates from. Used for display in UI. -const char* ts3plugin_keyDeviceName(const char* keyIdentifier) { - return NULL; -} - -// This function translates the given key identifier to a friendly key name for display in the UI -const char* ts3plugin_displayKeyText(const char* keyIdentifier) { - return NULL; -} - -// This is used internally as a prefix for hotkeys so we can store them without collisions. -// Should be unique across plugins. -const char* ts3plugin_keyPrefix() { - return NULL; -} - -/* Called when client custom nickname changed */ -void ts3plugin_onClientDisplayNameChanged(uint64 serverConnectionHandlerID, anyID clientID, const char* displayName, const char* uniqueClientIdentifier) { -} diff --git a/pluginsdk/src/plugin.h b/pluginsdk/src/plugin.h deleted file mode 100644 index f045cb4..0000000 --- a/pluginsdk/src/plugin.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * TeamSpeak 3 demo plugin - * - * Copyright (c) TeamSpeak Systems GmbH - */ - -#ifndef PLUGIN_H -#define PLUGIN_H - -#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) -#define PLUGINS_EXPORTDLL __declspec(dllexport) -#else -#define PLUGINS_EXPORTDLL __attribute__ ((visibility("default"))) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Required functions */ -PLUGINS_EXPORTDLL const char* ts3plugin_name(); -PLUGINS_EXPORTDLL const char* ts3plugin_version(); -PLUGINS_EXPORTDLL int ts3plugin_apiVersion(); -PLUGINS_EXPORTDLL const char* ts3plugin_author(); -PLUGINS_EXPORTDLL const char* ts3plugin_description(); -PLUGINS_EXPORTDLL void ts3plugin_setFunctionPointers(const struct TS3Functions funcs); -PLUGINS_EXPORTDLL int ts3plugin_init(); -PLUGINS_EXPORTDLL void ts3plugin_shutdown(); - -/* Optional functions */ -PLUGINS_EXPORTDLL int ts3plugin_offersConfigure(); -PLUGINS_EXPORTDLL void ts3plugin_configure(void* handle, void* qParentWidget); -PLUGINS_EXPORTDLL void ts3plugin_registerPluginID(const char* id); -PLUGINS_EXPORTDLL const char* ts3plugin_commandKeyword(); -PLUGINS_EXPORTDLL int ts3plugin_processCommand(uint64 serverConnectionHandlerID, const char* command); -PLUGINS_EXPORTDLL void ts3plugin_currentServerConnectionChanged(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL const char* ts3plugin_infoTitle(); -PLUGINS_EXPORTDLL void ts3plugin_infoData(uint64 serverConnectionHandlerID, uint64 id, enum PluginItemType type, char** data); -PLUGINS_EXPORTDLL void ts3plugin_freeMemory(void* data); -PLUGINS_EXPORTDLL int ts3plugin_requestAutoload(); -PLUGINS_EXPORTDLL void ts3plugin_initMenus(struct PluginMenuItem*** menuItems, char** menuIcon); -PLUGINS_EXPORTDLL void ts3plugin_initHotkeys(struct PluginHotkey*** hotkeys); - -/* Clientlib */ -PLUGINS_EXPORTDLL void ts3plugin_onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int newStatus, unsigned int errorNumber); -PLUGINS_EXPORTDLL void ts3plugin_onNewChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID); -PLUGINS_EXPORTDLL void ts3plugin_onNewChannelCreatedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier); -PLUGINS_EXPORTDLL void ts3plugin_onDelChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier); -PLUGINS_EXPORTDLL void ts3plugin_onChannelMoveEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 newChannelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier); -PLUGINS_EXPORTDLL void ts3plugin_onUpdateChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID); -PLUGINS_EXPORTDLL void ts3plugin_onUpdateChannelEditedEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier); -PLUGINS_EXPORTDLL void ts3plugin_onUpdateClientEvent(uint64 serverConnectionHandlerID, anyID clientID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier); -PLUGINS_EXPORTDLL void ts3plugin_onClientMoveEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* moveMessage); -PLUGINS_EXPORTDLL void ts3plugin_onClientMoveSubscriptionEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility); -PLUGINS_EXPORTDLL void ts3plugin_onClientMoveTimeoutEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* timeoutMessage); -PLUGINS_EXPORTDLL void ts3plugin_onClientMoveMovedEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID moverID, const char* moverName, const char* moverUniqueIdentifier, const char* moveMessage); -PLUGINS_EXPORTDLL void ts3plugin_onClientKickFromChannelEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage); -PLUGINS_EXPORTDLL void ts3plugin_onClientKickFromServerEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, const char* kickMessage); -PLUGINS_EXPORTDLL void ts3plugin_onClientIDsEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, anyID clientID, const char* clientName); -PLUGINS_EXPORTDLL void ts3plugin_onClientIDsFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onServerEditedEvent(uint64 serverConnectionHandlerID, anyID editerID, const char* editerName, const char* editerUniqueIdentifier); -PLUGINS_EXPORTDLL void ts3plugin_onServerUpdatedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL int ts3plugin_onServerErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage); -PLUGINS_EXPORTDLL void ts3plugin_onServerStopEvent(uint64 serverConnectionHandlerID, const char* shutdownMessage); -PLUGINS_EXPORTDLL int ts3plugin_onTextMessageEvent(uint64 serverConnectionHandlerID, anyID targetMode, anyID toID, anyID fromID, const char* fromName, const char* fromUniqueIdentifier, const char* message, int ffIgnored); -PLUGINS_EXPORTDLL void ts3plugin_onTalkStatusChangeEvent(uint64 serverConnectionHandlerID, int status, int isReceivedWhisper, anyID clientID); -PLUGINS_EXPORTDLL void ts3plugin_onConnectionInfoEvent(uint64 serverConnectionHandlerID, anyID clientID); -PLUGINS_EXPORTDLL void ts3plugin_onServerConnectionInfoEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelSubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelSubscribeFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelUnsubscribeEvent(uint64 serverConnectionHandlerID, uint64 channelID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelUnsubscribeFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelDescriptionUpdateEvent(uint64 serverConnectionHandlerID, uint64 channelID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelPasswordChangedEvent(uint64 serverConnectionHandlerID, uint64 channelID); -PLUGINS_EXPORTDLL void ts3plugin_onPlaybackShutdownCompleteEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onSoundDeviceListChangedEvent(const char* modeID, int playOrCap); -PLUGINS_EXPORTDLL void ts3plugin_onEditPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels); -PLUGINS_EXPORTDLL void ts3plugin_onEditPostProcessVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask); -PLUGINS_EXPORTDLL void ts3plugin_onEditMixedPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask); -PLUGINS_EXPORTDLL void ts3plugin_onEditCapturedVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, int* edited); -PLUGINS_EXPORTDLL void ts3plugin_onCustom3dRolloffCalculationClientEvent(uint64 serverConnectionHandlerID, anyID clientID, float distance, float* volume); -PLUGINS_EXPORTDLL void ts3plugin_onCustom3dRolloffCalculationWaveEvent(uint64 serverConnectionHandlerID, uint64 waveHandle, float distance, float* volume); -PLUGINS_EXPORTDLL void ts3plugin_onUserLoggingMessageEvent(const char* logMessage, int logLevel, const char* logChannel, uint64 logID, const char* logTime, const char* completeLogString); - -/* Clientlib rare */ -PLUGINS_EXPORTDLL void ts3plugin_onClientBanFromServerEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, anyID kickerID, const char* kickerName, const char* kickerUniqueIdentifier, uint64 time, const char* kickMessage); -PLUGINS_EXPORTDLL int ts3plugin_onClientPokeEvent(uint64 serverConnectionHandlerID, anyID fromClientID, const char* pokerName, const char* pokerUniqueIdentity, const char* message, int ffIgnored); -PLUGINS_EXPORTDLL void ts3plugin_onClientSelfVariableUpdateEvent(uint64 serverConnectionHandlerID, int flag, const char* oldValue, const char* newValue); -PLUGINS_EXPORTDLL void ts3plugin_onFileListEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path, const char* name, uint64 size, uint64 datetime, int type, uint64 incompletesize, const char* returnCode); -PLUGINS_EXPORTDLL void ts3plugin_onFileListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* path); -PLUGINS_EXPORTDLL void ts3plugin_onFileInfoEvent(uint64 serverConnectionHandlerID, uint64 channelID, const char* name, uint64 size, uint64 datetime); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, const char* name, int type, int iconID, int saveDB); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupListFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupByClientIDEvent(uint64 serverConnectionHandlerID, const char* name, uint64 serverGroupList, uint64 clientDatabaseID); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupClientListEvent(uint64 serverConnectionHandlerID, uint64 serverGroupID, uint64 clientDatabaseID, const char* clientNameIdentifier, const char* clientUniqueID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelGroupListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, const char* name, int type, int iconID, int saveDB); -PLUGINS_EXPORTDLL void ts3plugin_onChannelGroupListFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelGroupPermListEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip); -PLUGINS_EXPORTDLL void ts3plugin_onChannelGroupPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip); -PLUGINS_EXPORTDLL void ts3plugin_onChannelPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID); -PLUGINS_EXPORTDLL void ts3plugin_onClientPermListEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip); -PLUGINS_EXPORTDLL void ts3plugin_onClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID); -PLUGINS_EXPORTDLL void ts3plugin_onChannelClientPermListEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip); -PLUGINS_EXPORTDLL void ts3plugin_onChannelClientPermListFinishedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 clientDatabaseID); -PLUGINS_EXPORTDLL void ts3plugin_onClientChannelGroupChangedEvent(uint64 serverConnectionHandlerID, uint64 channelGroupID, uint64 channelID, anyID clientID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity); -PLUGINS_EXPORTDLL int ts3plugin_onServerPermissionErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, unsigned int failedPermissionID); -PLUGINS_EXPORTDLL void ts3plugin_onPermissionListGroupEndIDEvent(uint64 serverConnectionHandlerID, unsigned int groupEndID); -PLUGINS_EXPORTDLL void ts3plugin_onPermissionListEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, const char* permissionName, const char* permissionDescription); -PLUGINS_EXPORTDLL void ts3plugin_onPermissionListFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onPermissionOverviewEvent(uint64 serverConnectionHandlerID, uint64 clientDatabaseID, uint64 channelID, int overviewType, uint64 overviewID1, uint64 overviewID2, unsigned int permissionID, int permissionValue, int permissionNegated, int permissionSkip); -PLUGINS_EXPORTDLL void ts3plugin_onPermissionOverviewFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupClientAddedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity); -PLUGINS_EXPORTDLL void ts3plugin_onServerGroupClientDeletedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientName, const char* clientUniqueIdentity, uint64 serverGroupID, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity); -PLUGINS_EXPORTDLL void ts3plugin_onClientNeededPermissionsEvent(uint64 serverConnectionHandlerID, unsigned int permissionID, int permissionValue); -PLUGINS_EXPORTDLL void ts3plugin_onClientNeededPermissionsFinishedEvent(uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onFileTransferStatusEvent(anyID transferID, unsigned int status, const char* statusMessage, uint64 remotefileSize, uint64 serverConnectionHandlerID); -PLUGINS_EXPORTDLL void ts3plugin_onClientChatClosedEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity); -PLUGINS_EXPORTDLL void ts3plugin_onClientChatComposingEvent(uint64 serverConnectionHandlerID, anyID clientID, const char* clientUniqueIdentity); -PLUGINS_EXPORTDLL void ts3plugin_onServerLogEvent(uint64 serverConnectionHandlerID, const char* logMsg); -PLUGINS_EXPORTDLL void ts3plugin_onServerLogFinishedEvent(uint64 serverConnectionHandlerID, uint64 lastPos, uint64 fileSize); -PLUGINS_EXPORTDLL void ts3plugin_onMessageListEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, uint64 timestamp, int flagRead); -PLUGINS_EXPORTDLL void ts3plugin_onMessageGetEvent(uint64 serverConnectionHandlerID, uint64 messageID, const char* fromClientUniqueIdentity, const char* subject, const char* message, uint64 timestamp); -PLUGINS_EXPORTDLL void ts3plugin_onClientDBIDfromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID); -PLUGINS_EXPORTDLL void ts3plugin_onClientNamefromUIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName); -PLUGINS_EXPORTDLL void ts3plugin_onClientNamefromDBIDEvent(uint64 serverConnectionHandlerID, const char* uniqueClientIdentifier, uint64 clientDatabaseID, const char* clientNickName); -PLUGINS_EXPORTDLL void ts3plugin_onComplainListEvent(uint64 serverConnectionHandlerID, uint64 targetClientDatabaseID, const char* targetClientNickName, uint64 fromClientDatabaseID, const char* fromClientNickName, const char* complainReason, uint64 timestamp); -PLUGINS_EXPORTDLL void ts3plugin_onBanListEvent(uint64 serverConnectionHandlerID, uint64 banid, const char* ip, const char* name, const char* uid, const char* mytsid, uint64 creationTime, uint64 durationTime, const char* invokerName, uint64 invokercldbid, const char* invokeruid, const char* reason, int numberOfEnforcements, const char* lastNickName); -PLUGINS_EXPORTDLL void ts3plugin_onClientServerQueryLoginPasswordEvent(uint64 serverConnectionHandlerID, const char* loginPassword); -PLUGINS_EXPORTDLL void ts3plugin_onPluginCommandEvent(uint64 serverConnectionHandlerID, const char* pluginName, const char* pluginCommand, anyID invokerClientID, const char* invokerName, const char* invokerUniqueIdentity); -PLUGINS_EXPORTDLL void ts3plugin_onIncomingClientQueryEvent(uint64 serverConnectionHandlerID, const char* commandText); -PLUGINS_EXPORTDLL void ts3plugin_onServerTemporaryPasswordListEvent(uint64 serverConnectionHandlerID, const char* clientNickname, const char* uniqueClientIdentifier, const char* description, const char* password, uint64 timestampStart, uint64 timestampEnd, uint64 targetChannelID, const char* targetChannelPW); - -/* Client UI callbacks */ -PLUGINS_EXPORTDLL void ts3plugin_onAvatarUpdated(uint64 serverConnectionHandlerID, anyID clientID, const char* avatarPath); -PLUGINS_EXPORTDLL void ts3plugin_onMenuItemEvent(uint64 serverConnectionHandlerID, enum PluginMenuType type, int menuItemID, uint64 selectedItemID); -PLUGINS_EXPORTDLL void ts3plugin_onHotkeyEvent(const char* keyword); -PLUGINS_EXPORTDLL void ts3plugin_onHotkeyRecordedEvent(const char* keyword, const char* key); -PLUGINS_EXPORTDLL void ts3plugin_onClientDisplayNameChanged(uint64 serverConnectionHandlerID, anyID clientID, const char* displayName, const char* uniqueClientIdentifier); -PLUGINS_EXPORTDLL const char* ts3plugin_keyDeviceName(const char* keyIdentifier); -PLUGINS_EXPORTDLL const char* ts3plugin_displayKeyText(const char* keyIdentifier); -PLUGINS_EXPORTDLL const char* ts3plugin_keyPrefix(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/pluginsdk/src/test_plugin.sln b/pluginsdk/src/test_plugin.sln deleted file mode 100644 index 6e822ec..0000000 --- a/pluginsdk/src/test_plugin.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_plugin", "test_plugin.vcxproj", "{192D646D-748B-450B-AF3D-BF8EDD5FC897}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {192D646D-748B-450B-AF3D-BF8EDD5FC897}.Debug|Win32.ActiveCfg = Debug|Win32 - {192D646D-748B-450B-AF3D-BF8EDD5FC897}.Debug|Win32.Build.0 = Debug|Win32 - {192D646D-748B-450B-AF3D-BF8EDD5FC897}.Release|Win32.ActiveCfg = Release|Win32 - {192D646D-748B-450B-AF3D-BF8EDD5FC897}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/pluginsdk/src/test_plugin.vcxproj b/pluginsdk/src/test_plugin.vcxproj deleted file mode 100644 index 51907e1..0000000 --- a/pluginsdk/src/test_plugin.vcxproj +++ /dev/null @@ -1,99 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {192D646D-748B-450B-AF3D-BF8EDD5FC897} - test_plugin - Win32Proj - - - - DynamicLibrary - v120_xp - Unicode - - - DynamicLibrary - v120_xp - Unicode - - - - - - - - - - - - - <_ProjectFileVersion>12.0.30501.0 - - - \projects\teamspeak\plugins\ - $(Configuration)\ - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - - Disabled - ..\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;TEST_PLUGIN_EXPORTS;WINDOWS;WIN32_LEAN_AND_MEAN;NOFMOD;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - - Level3 - ProgramDatabase - - - true - Windows - - MachineX86 - - - - - WIN32;NDEBUG;_WINDOWS;_USRDLL;TEST_PLUGIN_EXPORTS;%(PreprocessorDefinitions) - MultiThreadedDLL - - Level3 - ProgramDatabase - ..\include;%(AdditionalIncludeDirectories) - - - Windows - - MachineX86 - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pluginsdk/src/test_plugin.vcxproj.filters b/pluginsdk/src/test_plugin.vcxproj.filters deleted file mode 100644 index 79cc68b..0000000 --- a/pluginsdk/src/test_plugin.vcxproj.filters +++ /dev/null @@ -1,53 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {424f4ce9-e47e-43e3-91bc-85bbfec2c680} - - - {d76dfa87-907d-4936-a5cf-59462dba95d7} - - - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files\teamspeak - - - Header Files\teamspeak - - - Header Files\teamspeak - - - Header Files\teamspeak - - - Header Files\teamspeak - - - Header Files\teamlog - - - Header Files - - - \ No newline at end of file diff --git a/teamlog/logtypes.go b/teamlog/logtypes.go index 1c375a3..44ac0be 100644 --- a/teamlog/logtypes.go +++ b/teamlog/logtypes.go @@ -3,7 +3,7 @@ package teamlog //go:generate stringer -type=LogType,LogLevel -output generated_logtypes_string.go /* -#cgo CFLAGS: -I../pluginsdk/include -I. +#cgo CFLAGS: -I. #include "teamlog/logtypes.h" */ import "C" diff --git a/teamspeak/clientlib_publicdefinitions.go b/teamspeak/clientlib_publicdefinitions.go index 3bb146f..f9a44be 100644 --- a/teamspeak/clientlib_publicdefinitions.go +++ b/teamspeak/clientlib_publicdefinitions.go @@ -1,7 +1,7 @@ package teamspeak /* -#cgo CFLAGS: -I../pluginsdk/include -I. +#cgo CFLAGS: -I. #include "teamspeak/clientlib_publicdefinitions.h" */ import "C" diff --git a/teamspeak/public_definitions.go b/teamspeak/public_definitions.go index 1047fbb..7cb0e61 100644 --- a/teamspeak/public_definitions.go +++ b/teamspeak/public_definitions.go @@ -1,7 +1,7 @@ package teamspeak /* -#cgo CFLAGS: -I../pluginsdk/include -I. +#cgo CFLAGS: -I. #include diff --git a/teamspeak/public_errors.go b/teamspeak/public_errors.go index 2a8d0e7..357b8f5 100644 --- a/teamspeak/public_errors.go +++ b/teamspeak/public_errors.go @@ -1,7 +1,7 @@ package teamspeak /* -#cgo CFLAGS: -I../pluginsdk/include -I. +#cgo CFLAGS: -I. #include "teamspeak/public_errors.h" */ diff --git a/teamspeak/public_errors_rare.go b/teamspeak/public_errors_rare.go index 350c34c..2535151 100644 --- a/teamspeak/public_errors_rare.go +++ b/teamspeak/public_errors_rare.go @@ -1,7 +1,7 @@ package teamspeak /* -#cgo CFLAGS: -I../pluginsdk/include -I. +#cgo CFLAGS: -I. #include "teamspeak/public_errors_rare.h" */ diff --git a/teamspeak/public_rare_definitions.go b/teamspeak/public_rare_definitions.go index 1cae2db..928d244 100644 --- a/teamspeak/public_rare_definitions.go +++ b/teamspeak/public_rare_definitions.go @@ -1,7 +1,7 @@ package teamspeak /* -#cgo CFLAGS: -I../pluginsdk/include -I. +#cgo CFLAGS: -I. #include "teamspeak/public_rare_definitions.h" diff --git a/ts3_functions.go b/ts3_functions.go index 6d60332..0e56e24 100644 --- a/ts3_functions.go +++ b/ts3_functions.go @@ -3,7 +3,7 @@ package ts3plugin //go:generate go run ./internal/generate/ts3_functions/main.go /* -#cgo CFLAGS: -I./pluginsdk/include -I. +#cgo CFLAGS: -I. #include // free #include "generated_ts3_function_wrappers.h" diff --git a/ts3plugin.go b/ts3plugin.go index 389c775..cd1e5db 100644 --- a/ts3plugin.go +++ b/ts3plugin.go @@ -1,8 +1,6 @@ package ts3plugin /* -#cgo CFLAGS: -I${SRCDIR}/pluginsdk/include - #include // uint types #include // free From f77651d9122681c4b5995a9832105c1d406c5e46 Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Thu, 15 Jun 2023 04:40:04 +0200 Subject: [PATCH 3/6] License under BSD 3-Clause with notice of licensing complications Fixes #14. --- LICENSE.txt | 28 ++++++++++++++++++++++++++++ README.md | 13 +++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..445eb38 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2023 Carl Kittelberger + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 8763c9a..f1bbd55 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,16 @@ automations. To download it just click "Code" and then "Download ZIP" there. - Having the `include/` directory exported as part of environment variable `CGO_CPPFLAGS` (e.g. `-I/path/to/your/sdk/copy/include/`). + +## License + +This library has been licensed under the BSD 3-Clause License in hopes to keep +it entirely compatible with the original TeamSpeak3 Plugin SDK. + +There are known open-source licensing complications in regards to the +TeamSpeak3 Plugin SDK itself (see [ts3client-pluginsdk#3]) which I am trying +to comply with on best efforts and with best intentions in mind. If a +violation of copyright or license exists in this repository, do contact me +either via GitHub issues or via the e-mail used for my Git commits. + +[ts3client-pluginsdk#3]: https://github.com/TeamSpeak-Systems/ts3client-pluginsdk/issues/3 From c83321caa7f49c2cdfb28dc33e08bb491217224a Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Thu, 15 Jun 2023 05:29:53 +0200 Subject: [PATCH 4/6] Change signature for Configure method. --- ts3plugin.go | 3 ++- ts3plugin_go_types.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ts3plugin.go b/ts3plugin.go index cd1e5db..40a6516 100644 --- a/ts3plugin.go +++ b/ts3plugin.go @@ -17,6 +17,7 @@ typedef struct TS3Functions TS3Functions; */ import "C" + import ( "fmt" "time" @@ -169,7 +170,7 @@ func ts3plugin_offersConfigure() C.int { //export ts3plugin_configure func ts3plugin_configure(handle *C.char, qParentWidget *C.char) { - notYetImplemented("ts3plugin_configure") + Configure(unsafe.Pointer(handle), unsafe.Pointer(qParentWidget)) } //export ts3plugin_registerPluginID diff --git a/ts3plugin_go_types.go b/ts3plugin_go_types.go index a32bcde..2d8066b 100644 --- a/ts3plugin_go_types.go +++ b/ts3plugin_go_types.go @@ -2,6 +2,7 @@ package ts3plugin import ( "time" + "unsafe" "github.com/icedream/go-ts3plugin/teamlog" "github.com/icedream/go-ts3plugin/teamspeak" @@ -30,7 +31,7 @@ var ( Init func() (ok bool) Shutdown func() OffersConfigure func() PluginConfigureOffer - Configure func(handle byte, qParentWidget byte) + Configure func(handle, qParentWidget unsafe.Pointer) ProcessCommand func(serverConnectionHandlerID uint64, command string) (handled bool) CurrentServerConnectionChanged func(serverConnectionHandlerID uint64) From 1e9b1d42e0a83696d43fea37d95f6e5ecc460a94 Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Thu, 15 Jun 2023 05:30:26 +0200 Subject: [PATCH 5/6] Fix several constants all being set to zero instead of incrementing values. --- plugin_definitions.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugin_definitions.go b/plugin_definitions.go index a4fb312..e5ef19d 100644 --- a/plugin_definitions.go +++ b/plugin_definitions.go @@ -13,22 +13,22 @@ import "C" type PluginConfigureOffer int const ( - PLUGIN_OFFERS_NO_CONFIGURE = 0 /* Plugin does not implement ts3plugin_configure */ - PLUGIN_OFFERS_CONFIGURE_NEW_THREAD /* Plugin does implement ts3plugin_configure and requests to run this function in an own thread */ - PLUGIN_OFFERS_CONFIGURE_QT_THREAD /* Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread */ + PLUGIN_OFFERS_NO_CONFIGURE = iota /* Plugin does not implement ts3plugin_configure */ + PLUGIN_OFFERS_CONFIGURE_NEW_THREAD /* Plugin does implement ts3plugin_configure and requests to run this function in an own thread */ + PLUGIN_OFFERS_CONFIGURE_QT_THREAD /* Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread */ ) type PluginMessageTarget int const ( - PLUGIN_MESSAGE_TARGET_SERVER = 0 + PLUGIN_MESSAGE_TARGET_SERVER = iota PLUGIN_MESSAGE_TARGET_CHANNEL ) type PluginItemType int const ( - PLUGIN_SERVER = 0 + PLUGIN_SERVER = iota PLUGIN_CHANNEL PLUGIN_CLIENT ) @@ -36,7 +36,7 @@ const ( type PluginMenuType int const ( - PLUGIN_MENU_TYPE_GLOBAL = 0 + PLUGIN_MENU_TYPE_GLOBAL = iota PLUGIN_MENU_TYPE_CHANNEL PLUGIN_MENU_TYPE_CLIENT ) @@ -68,7 +68,7 @@ type PluginBookmarkList struct { type PluginGuiProfile int const ( - PLUGIN_GUI_SOUND_CAPTURE PluginGuiProfile = 0 + PLUGIN_GUI_SOUND_CAPTURE PluginGuiProfile = iota PLUGIN_GUI_SOUND_PLAYBACK PLUGIN_GUI_HOTKEY PLUGIN_GUI_SOUNDPACK @@ -78,7 +78,7 @@ const ( type PluginConnectTab int const ( - PLUGIN_CONNECT_TAB_NEW PluginConnectTab = 0 + PLUGIN_CONNECT_TAB_NEW PluginConnectTab = iota PLUGIN_CONNECT_TAB_CURRENT PLUGIN_CONNECT_TAB_NEW_IF_CURRENT_CONNECTED ) From 0a7646022ee34d858fc61ceae9498dd096914339 Mon Sep 17 00:00:00 2001 From: Carl Kittelberger Date: Thu, 15 Jun 2023 05:31:22 +0200 Subject: [PATCH 6/6] Reformat code. --- ts3plugin_go_types.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/ts3plugin_go_types.go b/ts3plugin_go_types.go index 2d8066b..c38f678 100644 --- a/ts3plugin_go_types.go +++ b/ts3plugin_go_types.go @@ -18,14 +18,10 @@ var ( InfoTitle string ) -var ( - RequestAutoload = false -) +var RequestAutoload = false -var ( - // Will be set by TeamSpeak after plugin is loaded. - pluginID string -) +// Will be set by TeamSpeak after plugin is loaded. +var pluginID string var ( Init func() (ok bool) @@ -69,9 +65,7 @@ var ( OnEditPostProcessVoiceDataEvent func(serverConnectionHandlerID uint64, clientID teamspeak.AnyID, samples *Samples, channelSpeakers []uint, channelFillMask *uint) ) -var ( - functions *TS3Functions -) +var functions *TS3Functions func Functions() *TS3Functions { return functions

Introduction

TeamSpeak 3 is a scalable Voice-Over-IP application consisting of client and server software. TeamSpeak is generally regarded as the leading VoIP system offering a superior voice quality, scalability and usability.

The cross-platform Software Development Kit allows the easy integration of the TeamSpeak client and server technology into own applications.

Tis document provides an introduction to client-side programming with the TeamSpeak 3 SDK, the so-called Client Lib. This library encapsulates client-side functionality while keeping the user interface separated and modular.