Advertisement
Hemirt

Untitled

Jun 24th, 2016
472
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 48.51 KB | None | 0 0
  1. /*
  2.  * TeamSpeak 3 client sample
  3.  *
  4.  * Copyright (c) 2007-2014 TeamSpeak Systems GmbH
  5.  */
  6.  
  7. #ifdef _WIN32
  8. #define _CRT_SECURE_NO_WARNINGS
  9. #pragma warning(disable : 4996)
  10. #include <Windows.h>
  11. #include <conio.h>
  12. #else
  13. #include <unistd.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #endif
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <limits.h>
  20.  
  21. #include <teamspeak/public_definitions.h>
  22. #include <teamspeak/public_errors.h>
  23. #include <teamspeak/clientlib_publicdefinitions.h>
  24. #include <teamspeak/clientlib.h>
  25.  
  26. #define DEFAULT_VIRTUAL_SERVER 1
  27. #define NAME_BUFSIZE 1024
  28. #define CHANNEL_PASSWORD_BUFSIZE 1024
  29.  
  30. #define CHECK_ERROR(x) if((error = x) != ERROR_ok) { goto on_error; }
  31. #define IDENTITY_BUFSIZE 1024
  32.  
  33. #ifdef _WIN32
  34. #define snprintf sprintf_s
  35. #define SLEEP(x) Sleep(x)
  36. #else
  37. #define SLEEP(x) usleep(x*1000)
  38. #endif
  39.  
  40. /* This is a global variable to indicate if sound needs to be recorded.
  41.    Normally one would have thread synchronization with locks etc. for
  42.    thread safety. In the intterest of simplicity, this sample uses the
  43.    most simple way to safely record, using this variable
  44. */
  45. int recordSound = 0;
  46.  
  47. /* For voice activation detection demo */
  48. uint64 vadTestscHandlerID;
  49. int vadTestTalkStatus = 0;
  50.  
  51. /* Enable to use custom encryption */
  52. /* #define USE_CUSTOM_ENCRYPTION
  53. #define CUSTOM_CRYPT_KEY 123 */
  54.  
  55. /* Uncomment "#define CUSTOM_PASSWORDS" to try custom passwords.
  56.  * Please note that you have to do the same on the server demo too */
  57. /* #define CUSTOM_PASSWORDS */
  58.  
  59. /* a struct used for sound recording */
  60. struct WaveHeader {
  61.     /* Riff chunk */
  62.     char riffId[4];  
  63.     unsigned int len;
  64.     char riffType[4];  
  65.  
  66.     /* Format chunk */
  67.     char fmtId[4];  // 'fmt '
  68.     unsigned int fmtLen;
  69.     unsigned short formatTag;
  70.     unsigned short channels;
  71.     unsigned int samplesPerSec;
  72.     unsigned int avgBytesPerSec;
  73.     unsigned short blockAlign;
  74.     unsigned short bitsPerSample;
  75.  
  76.     /* Data chunk */
  77.     char dataId[4];  // 'data'
  78.     unsigned int dataLen;
  79. };
  80.  
  81. /*
  82.  * Callback for connection status change.
  83.  * Connection status switches through the states STATUS_DISCONNECTED, STATUS_CONNECTING, STATUS_CONNECTED and STATUS_CONNECTION_ESTABLISHED.
  84.  *
  85.  * Parameters:
  86.  *   serverConnectionHandlerID - Server connection handler ID
  87.  *   newStatus                 - New connection status, see the enum ConnectStatus in clientlib_publicdefinitions.h
  88.  *   errorNumber               - Error code. Should be zero when connecting or actively disconnection.
  89.  *                               Contains error state when losing connection.
  90.  */
  91. void onConnectStatusChangeEvent(uint64 serverConnectionHandlerID, int newStatus, unsigned int errorNumber) {
  92.     printf("Connect status changed: %llu %d %d\n", (unsigned long long)serverConnectionHandlerID, newStatus, errorNumber);
  93.     /* Failed to connect ? */
  94.     if(newStatus == STATUS_DISCONNECTED && errorNumber == ERROR_failed_connection_initialisation) {
  95.         printf("Looks like there is no server running.\n");
  96.     }
  97. }
  98.  
  99. /*
  100.  * Callback for current channels being announced to the client after connecting to a server.
  101.  *
  102.  * Parameters:
  103.  *   serverConnectionHandlerID - Server connection handler ID
  104.  *   channelID                 - ID of the announced channel
  105.  *    channelParentID           - ID of the parent channel
  106.  */
  107. void onNewChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID) {
  108.     /* Query channel name from channel ID */
  109.     char* name;
  110.     unsigned int error;
  111.  
  112.     printf("onNewChannelEvent: %llu %llu %llu\n", (unsigned long long)serverConnectionHandlerID, (unsigned long long)channelID, (unsigned long long)channelParentID);
  113.     if((error = ts3client_getChannelVariableAsString(serverConnectionHandlerID, channelID, CHANNEL_NAME, &name)) == ERROR_ok) {
  114.         printf("New channel: %llu %s \n", (unsigned long long)channelID, name);
  115.         ts3client_freeMemory(name);  /* Release dynamically allocated memory only if function succeeded */
  116.     } else {
  117.         char* errormsg;
  118.         if(ts3client_getErrorMessage(error, &errormsg) == ERROR_ok) {
  119.             printf("Error getting channel name in onNewChannelEvent: %s\n", errormsg);
  120.             ts3client_freeMemory(errormsg);
  121.         }
  122.     }
  123. }
  124.  
  125. /*
  126.  * Callback for just created channels.
  127.  *
  128.  * Parameters:
  129.  *   serverConnectionHandlerID - Server connection handler ID
  130.  *   channelID                 - ID of the announced channel
  131.  *   channelParentID           - ID of the parent channel
  132.  *    invokerID                 - ID of the client who created the channel
  133.  *   invokerName               - Name of the client who created the channel
  134.  */
  135. void onNewChannelCreatedEvent(uint64 serverConnectionHandlerID, uint64 channelID, uint64 channelParentID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
  136.     char* name;
  137.  
  138.     /* Query channel name from channel ID */
  139.     if(ts3client_getChannelVariableAsString(serverConnectionHandlerID, channelID, CHANNEL_NAME, &name) != ERROR_ok)
  140.         return;
  141.     printf("New channel created: %s \n", name);
  142.     ts3client_freeMemory(name);  /* Release dynamically allocated memory only if function succeeded */
  143. }
  144.  
  145. /*
  146.  * Callback when a channel was deleted.
  147.  *
  148.  * Parameters:
  149.  *   serverConnectionHandlerID - Server connection handler ID
  150.  *   channelID                 - ID of the deleted channel
  151.  *   invokerID                 - ID of the client who deleted the channel
  152.  *   invokerName               - Name of the client who deleted the channel
  153.  */
  154. void onDelChannelEvent(uint64 serverConnectionHandlerID, uint64 channelID, anyID invokerID, const char* invokerName, const char* invokerUniqueIdentifier) {
  155.     printf("Channel ID %llu deleted by %s (%u)\n", (unsigned long long)channelID, invokerName, invokerID);
  156. }
  157.  
  158. /*
  159.  * Called when a client joins, leaves or moves to another channel.
  160.  *
  161.  * Parameters:
  162.  *   serverConnectionHandlerID - Server connection handler ID
  163.  *   clientID                  - ID of the moved client
  164.  *   oldChannelID              - ID of the old channel left by the client
  165.  *   newChannelID              - ID of the new channel joined by the client
  166.  *   visibility                - Visibility of the moved client. See the enum Visibility in clientlib_publicdefinitions.h
  167.  *                               Values: ENTER_VISIBILITY, RETAIN_VISIBILITY, LEAVE_VISIBILITY
  168.  */
  169. void onClientMoveEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* moveMessage) {
  170.     printf("ClientID %u moves from channel %llu to %llu with message %s\n", clientID, (unsigned long long)oldChannelID, (unsigned long long)newChannelID, moveMessage);
  171. }
  172.  
  173. /*
  174.  * Callback for other clients in current and subscribed channels being announced to the client.
  175.  *
  176.  * Parameters:
  177.  *   serverConnectionHandlerID - Server connection handler ID
  178.  *   clientID                  - ID of the announced client
  179.  *   oldChannelID              - ID of the subscribed channel where the client left visibility
  180.  *   newChannelID              - ID of the subscribed channel where the client entered visibility
  181.  *   visibility                - Visibility of the announced client. See the enum Visibility in clientlib_publicdefinitions.h
  182.  *                               Values: ENTER_VISIBILITY, RETAIN_VISIBILITY, LEAVE_VISIBILITY
  183.  */
  184. void onClientMoveSubscriptionEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility) {
  185.     char* name;
  186.  
  187.     /* Query client nickname from ID */
  188.     if(ts3client_getClientVariableAsString(serverConnectionHandlerID, clientID, CLIENT_NICKNAME, &name) != ERROR_ok)
  189.         return;
  190.     printf("New client: %s \n", name);
  191.     ts3client_freeMemory(name);  /* Release dynamically allocated memory only if function succeeded */
  192. }
  193.  
  194. /*
  195.  * Called when a client drops his connection.
  196.  *
  197.  * Parameters:
  198.  *   serverConnectionHandlerID - Server connection handler ID
  199.  *   clientID                  - ID of the moved client
  200.  *   oldChannelID              - ID of the channel the leaving client was previously member of
  201.  *   newChannelID              - 0, as client is leaving
  202.  *   visibility                - Always LEAVE_VISIBILITY
  203.  *   timeoutMessage            - Optional message giving the reason for the timeout
  204.  */
  205. void onClientMoveTimeoutEvent(uint64 serverConnectionHandlerID, anyID clientID, uint64 oldChannelID, uint64 newChannelID, int visibility, const char* timeoutMessage) {
  206.     printf("ClientID %u timeouts with message %s\n", clientID, timeoutMessage);
  207. }
  208.  
  209. /*
  210.  * This event is called when a client starts or stops talking.
  211.  *
  212.  * Parameters:
  213.  *   serverConnectionHandlerID - Server connection handler ID
  214.  *   status                    - 1 if client starts talking, 0 if client stops talking
  215.  *   isReceivedWhisper         - 1 if this event was caused by whispering, 0 if caused by normal talking
  216.  *   clientID                  - ID of the client who announced the talk status change
  217.  */
  218. void onTalkStatusChangeEvent(uint64 serverConnectionHandlerID, int status, int isReceivedWhisper, anyID clientID) {
  219.     char* name;
  220.  
  221.     /* If we are currently in configure-microphone mode, remember the status and use it later in the loop in configureMicrophone() */
  222.     if(serverConnectionHandlerID == vadTestscHandlerID) {
  223.         vadTestTalkStatus = status;
  224.         return;
  225.     }
  226.  
  227.     /* Query client nickname from ID */
  228.     if(ts3client_getClientVariableAsString(serverConnectionHandlerID, clientID, CLIENT_NICKNAME, &name) != ERROR_ok)
  229.         return;
  230.     if(status == STATUS_TALKING) {
  231.         printf("Client \"%s\" starts talking.\n", name);
  232.     } else {
  233.         printf("Client \"%s\" stops talking.\n", name);
  234.     }
  235.     ts3client_freeMemory(name);  /* Release dynamically allocated memory only if function succeeded */
  236. }
  237.  
  238. /*
  239.  * This event is called when another client starts whispering to own client. Own client can decide to accept or deny
  240.  * receiving the whisper by adding the sending client to the whisper allow list. If not added, whispering is blocked.
  241.  *
  242.  * Parameters:
  243.  *   serverConnectionHandlerID - Server connection handler ID
  244.  *   clientID                  - ID of the whispering client
  245.  */
  246. void onIgnoredWhisperEvent(uint64 serverConnectionHandlerID, anyID clientID) {
  247.     unsigned int error;
  248.  
  249.     /* Add sending client to whisper allow list so own client will hear the voice data.
  250.      * It is sufficient to add a clientID only once, not everytime this event is called. However it won't
  251.      * hurt to add the same clientID to the allow list repeatedly, but is is not necessary. */
  252.     if((error = ts3client_allowWhispersFrom(serverConnectionHandlerID, clientID)) != ERROR_ok) {
  253.         printf("Error setting client on whisper allow list: %u\n", error);
  254.     }
  255.     printf("Added client %d to whisper allow list\n", clientID);
  256. }
  257.  
  258. void onServerErrorEvent(uint64 serverConnectionHandlerID, const char* errorMessage, unsigned int error, const char* returnCode, const char* extraMessage) {
  259.     printf("Error for server %llu: %s (%u) %s\n", (unsigned long long)serverConnectionHandlerID, errorMessage, error, extraMessage);
  260. }
  261.  
  262. /*
  263.  * Callback for user-defined logging.
  264.  *
  265.  * Parameter:
  266.  *   logMessage        - Log message text
  267.  *   logLevel          - Severity of log message
  268.  *   logChannel        - Custom text to categorize the message channel
  269.  *   logID             - Virtual server ID giving the virtual server source of the log event
  270.  *   logTime           - String with the date and time the log entry occured
  271.  *   completeLogString - Verbose log message including all previous parameters for convinience
  272.  */
  273. void onUserLoggingMessageEvent(const char* logMessage, int logLevel, const char* logChannel, uint64 logID, const char* logTime, const char* completeLogString) {
  274.     /* Your custom error display here... */
  275.     /* printf("LOG: %s\n", completeLogString); */
  276.     if(logLevel == LogLevel_CRITICAL) {
  277.         exit(1);  /* Your custom handling of critical errors */
  278.     }
  279. }
  280.  
  281. /*
  282.  * Callback allowing to apply custom encryption to outgoing packets.
  283.  * Using this function is optional. Do not implement if you want to handle the TeamSpeak 3 SDK encryption.
  284.  *
  285.  * Parameters:
  286.  *   dataToSend - Pointer to an array with the outgoing data to be encrypted
  287.  *   sizeOfData - Pointer to an integer value containing the size of the data array
  288.  *
  289.  * Apply your custom encryption to the data array. If the encrypted data is smaller than sizeOfData, write
  290.  * your encrypted data into the existing memory of dataToSend. If your encrypted data is larger, you need
  291.  * to allocate memory and redirect the pointer dataToSend. You need to take care of freeing your own allocated
  292.  * memory yourself. The memory allocated by the SDK, to which dataToSend is originally pointing to, must not
  293.  * be freed.
  294.  *
  295.  */
  296. void onCustomPacketEncryptEvent(char** dataToSend, unsigned int* sizeOfData) {
  297. #ifdef USE_CUSTOM_ENCRYPTION
  298.     unsigned int i;
  299.     for(i = 0; i < *sizeOfData; i++) {
  300.         (*dataToSend)[i] ^= CUSTOM_CRYPT_KEY;
  301.     }
  302. #endif
  303. }
  304.  
  305. /*
  306.  * Callback allowing to apply custom encryption to incoming packets
  307.  * Using this function is optional. Do not implement if you want to handle the TeamSpeak 3 SDK encryption.
  308.  *
  309.  * Parameters:
  310.  *   dataToSend - Pointer to an array with the received data to be decrypted
  311.  *   sizeOfData - Pointer to an integer value containing the size of the data array
  312.  *
  313.  * Apply your custom decryption to the data array. If the decrypted data is smaller than dataReceivedSize, write
  314.  * your decrypted data into the existing memory of dataReceived. If your decrypted data is larger, you need
  315.  * to allocate memory and redirect the pointer dataReceived. You need to take care of freeing your own allocated
  316.  * memory yourself. The memory allocated by the SDK, to which dataReceived is originally pointing to, must not
  317.  * be freed.
  318.  */
  319. void onCustomPacketDecryptEvent(char** dataReceived, unsigned int* dataReceivedSize) {
  320. #ifdef USE_CUSTOM_ENCRYPTION
  321.     unsigned int i;
  322.     for(i = 0; i < *dataReceivedSize; i++) {
  323.         (*dataReceived)[i] ^= CUSTOM_CRYPT_KEY;
  324.     }
  325. #endif
  326. }
  327.  
  328. /*
  329.  * Callback allowing access to voice data after it has been mixed by TeamSpeak 3
  330.  * This event can be used to alter/add to the voice data being played by TeamSpeak 3.
  331.  * But here we use it to record the voice data to a wave file.
  332.  *
  333.  * Parameters:
  334.  *   serverConnectionHandlerID - Server connection handler ID
  335.  *   samples - Pointer to a buffer containg 16 bit voice data samples at 48000 Hz. Channels are interleaved.
  336.  *   sampleCount - The number of samples 1 channel of sample data contains.
  337.  *   channels - The number of channels the sample data contains.
  338.  *   channelSpeakerArray - A bitmask of the speakers for each channel.
  339.  *   channelFillMask - A bitmask of channels that actually have valid data.
  340.  *
  341.  * -The size of the data "samples" points to is: sizeof(short)*sampleCount*channels
  342.  * -channelSpeakerArray uses SPEAKER_ defined in public_definitions.h
  343.  * -In the interrest of optimizations, a channel only contains data, if there is sound data for it. For example:
  344.  * in 5.1 or 7.1 we (almost) never have data for the subwoofer. Teamspeak then leaves the data in this channel
  345.  * undefined. This is more efficient for mixing.
  346.  * This implementation will record sound to a 2 channel (stereo) wave file. This sample assumes there is only
  347.  * 1 connection to a server
  348.  * Hint: Normally you would want to defer the writing to an other thread because this callback is very time sensitive
  349.  */
  350. void onEditMixedPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, short* samples, int sampleCount, int channels, const unsigned int* channelSpeakerArray, unsigned int* channelFillMask){
  351.     #define OUTPUTCHANNELS 2
  352.     static FILE *pfile = NULL;
  353.     static struct WaveHeader header = { {'R','I','F','F'}, 0, {'W','A','V','E'}, {'f','m','t',' '}, 16, 1, 2, 48000, 48000*(16/2)*2, (16/2)*2, 16, {'d','a','t','a'}, 0 };
  354.  
  355.     int currentSampleMix[OUTPUTCHANNELS]; /*a per channel/sample mix buffer*/
  356.     int channelCount[OUTPUTCHANNELS] = {0,0}; /*how many input channels does the output channel contain */
  357.    
  358.     int currentInChannel;
  359.     int currentOutChannel;
  360.     int currentSample;
  361.  
  362.     /*for clipping*/
  363.     short shortval;
  364.     int   intval;
  365.  
  366.     short* outputBuffer;
  367.  
  368.     int leftChannelMask  = SPEAKER_FRONT_LEFT  | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT  | SPEAKER_FRONT_LEFT_OF_CENTER  | SPEAKER_BACK_CENTER | SPEAKER_SIDE_LEFT  | SPEAKER_TOP_CENTER | SPEAKER_TOP_FRONT_LEFT  | SPEAKER_TOP_FRONT_CENTER | SPEAKER_TOP_BACK_LEFT  | SPEAKER_TOP_BACK_CENTER;
  369.     int rightChannelMask = SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_RIGHT_OF_CENTER | SPEAKER_BACK_CENTER | SPEAKER_SIDE_RIGHT | SPEAKER_TOP_CENTER | SPEAKER_TOP_FRONT_RIGHT | SPEAKER_TOP_FRONT_CENTER | SPEAKER_TOP_BACK_RIGHT | SPEAKER_TOP_BACK_CENTER;
  370.    
  371.     /*detect state changes*/
  372.     if (recordSound && (pfile == NULL)){
  373.         /*start recording*/
  374.         header.len = 0;
  375.         header.dataLen = 0;
  376.         if((pfile = fopen("recordedvoices.wav", "wb")) == NULL) return;
  377.         fwrite(&header, sizeof(struct WaveHeader), 1, pfile);
  378.     } else if (!recordSound && (pfile != NULL)){
  379.         /*stop recording*/
  380.         header.len = sizeof(struct WaveHeader)+header.dataLen - 8;
  381.         fseek (pfile, 0, SEEK_SET);
  382.         fwrite(&header, sizeof(struct WaveHeader), 1, pfile);
  383.         fclose(pfile);
  384.         pfile = NULL;
  385.     }
  386.  
  387.     /*if there is nothing to do, quit*/
  388.     if (pfile == NULL || sampleCount == 0 || channels == 0) return;
  389.  
  390.     /* initialize channel mixing */
  391.     currentInChannel = 0;
  392.     /*loop over all possible speakers*/
  393.     for (currentInChannel=0; currentInChannel < channels; ++currentInChannel) {
  394.         /*if the speaker has actual data*/
  395.         if ((*channelFillMask & (1<<currentInChannel)) != 0){
  396.             /*add to the outChannelSpeakerSet*/
  397.             if ((channelSpeakerArray[currentInChannel] & leftChannelMask) != 0) channelCount[0]++;
  398.             if ((channelSpeakerArray[currentInChannel] & rightChannelMask) != 0) channelCount[1]++;
  399.         }
  400.     }
  401.  
  402.     /*get the outbut buffer*/
  403.     outputBuffer = (short*) malloc( sizeof(short)*sampleCount*2 /*output channels*/);
  404.  
  405.     /* hint: if channelCount is 0 for all channels, we could write a zero buffer and quit here */
  406.  
  407.     /*mix the samples*/
  408.     for (currentSample = 0; currentSample < sampleCount; currentSample++){
  409.         currentSampleMix[0] = currentSampleMix[1] = 0;
  410.        
  411.         /*loop over all channels in this frame */
  412.         for(currentInChannel =0; currentInChannel < channels; currentInChannel++){
  413.             if ((channelSpeakerArray[currentInChannel] & leftChannelMask)  != 0) currentSampleMix[0] += samples[ (currentSample*channels)+currentInChannel ];
  414.             if ((channelSpeakerArray[currentInChannel] & rightChannelMask) != 0) currentSampleMix[1] += samples[ (currentSample*channels)+currentInChannel ];
  415.         }
  416.        
  417.         /*collected all samples, store mixed sample */
  418.         for (currentOutChannel = 0; currentOutChannel < OUTPUTCHANNELS; currentOutChannel++){
  419.             if (channelCount[currentOutChannel] == 0){
  420.                 outputBuffer[ (currentSample*OUTPUTCHANNELS) + currentOutChannel] = 0;
  421.             } else {
  422.                 /*clip*/
  423.                 intval = currentSampleMix[currentOutChannel]/channelCount[currentOutChannel];
  424.                 if (intval >= SHRT_MAX) shortval = SHRT_MAX;
  425.                 else if (intval <= SHRT_MIN) shortval = SHRT_MIN;
  426.                 else shortval = (short) intval;
  427.                 /*store*/
  428.                 outputBuffer[ (currentSample*OUTPUTCHANNELS) + currentOutChannel] = shortval;
  429.             }
  430.         }
  431.     }
  432.  
  433.     /*write data & update header */
  434.     fwrite(outputBuffer, sampleCount*sizeof(short)*OUTPUTCHANNELS, 1, pfile);
  435.     header.dataLen += sampleCount*sizeof(short)*OUTPUTCHANNELS;
  436.  
  437.     /*free buffer*/
  438.     free(outputBuffer);
  439. }
  440.  
  441. #ifdef CUSTOM_PASSWORDS
  442. /*
  443.  * Called to encrypt channel and server passwords
  444.  *
  445.  * In this example, we do not do any encryption. That way we have clear
  446.  * text passwords on the server.
  447.  *
  448.  * Parameters:
  449.  *   serverConnectionHandlerID - Server connection handler ID.
  450.  *   plaintext - the clear text password
  451.  *   encryptedText - pointer to a buffer to store the encrypted password
  452.  *   encryptedTextByteSize - the size of the encryptedText buffer
  453.  */
  454. void onClientPasswordEncrypt(uint64 serverConnectionHandlerID, const char* plaintext, char* encryptedText, int encryptedTextByteSize){
  455.     int pt_len;
  456.  
  457.     printf("onClientPasswordEncrypt called\n");
  458.  
  459.     pt_len = strlen(plaintext);
  460.     if (encryptedTextByteSize < pt_len-1) pt_len = encryptedTextByteSize-1;
  461.  
  462.     memcpy(encryptedText, plaintext, pt_len);
  463.     encryptedText[pt_len]=0;
  464. }
  465. #endif
  466.  
  467. /*
  468.  * Print all channels of the given virtual server
  469.  */
  470. void showChannels(uint64 serverConnectionHandlerID) {
  471.     uint64 *ids;
  472.     int i;
  473.     unsigned int error;
  474.  
  475.     printf("\nList of channels on virtual server %llu:\n", (unsigned long long)serverConnectionHandlerID);
  476.     if((error = ts3client_getChannelList(serverConnectionHandlerID, &ids)) != ERROR_ok) {  /* Get array of channel IDs */
  477.         printf("Error getting channel list: %d\n", error);
  478.         return;
  479.     }
  480.     if(!ids[0]) {
  481.         printf("No channels\n\n");
  482.         ts3client_freeMemory(ids);
  483.         return;
  484.     }
  485.     for(i=0; ids[i]; i++) {
  486.         char* name;
  487.         if((error = ts3client_getChannelVariableAsString(serverConnectionHandlerID, ids[i], CHANNEL_NAME, &name)) != ERROR_ok) {  /* Query channel name */
  488.             printf("Error getting channel name: %d\n", error);
  489.             break;
  490.         }
  491.         printf("%llu - %s\n", (unsigned long long)ids[i], name);
  492.         ts3client_freeMemory(name);
  493.     }
  494.     printf("\n");
  495.  
  496.     ts3client_freeMemory(ids);  /* Release array */
  497. }
  498.  
  499. /*
  500.  * Print all clients on the given virtual server in the specified channel
  501.  */
  502. void showChannelClients(uint64 serverConnectionHandlerID, uint64 channelID) {
  503.     anyID* ids;
  504.     anyID ownClientID;
  505.     int i;
  506.     unsigned int error;
  507.  
  508.     printf("\nList of clients in channel %llu on virtual server %llu:\n", (unsigned long long)channelID, (unsigned long long)serverConnectionHandlerID);
  509.     if((error = ts3client_getChannelClientList(serverConnectionHandlerID, channelID, &ids)) != ERROR_ok) {  /* Get array of client IDs */
  510.         printf("Error getting client list for channel %llu: %d\n", (unsigned long long)channelID, error);
  511.         return;
  512.     }
  513.     if(!ids[0]) {
  514.         printf("No clients\n\n");
  515.         ts3client_freeMemory(ids);
  516.         return;
  517.     }
  518.  
  519.     /* Get own clientID as we need to call CLIENT_FLAG_TALKING with getClientSelfVariable for own client */
  520.     if((error = ts3client_getClientID(serverConnectionHandlerID, &ownClientID)) != ERROR_ok) {
  521.         printf("Error querying own client ID: %d\n", error);
  522.         return;
  523.     }
  524.  
  525.     for(i=0; ids[i]; i++) {
  526.         char* name;
  527.         int talkStatus;
  528.  
  529.         if((error = ts3client_getClientVariableAsString(serverConnectionHandlerID, ids[i], CLIENT_NICKNAME, &name)) != ERROR_ok) {  /* Query client nickname... */
  530.             printf("Error querying client nickname: %d\n", error);
  531.             break;
  532.         }
  533.        
  534.         if(ids[i] == ownClientID) {  /* CLIENT_FLAG_TALKING must be queried with getClientSelfVariable for own client */
  535.             if((error = ts3client_getClientSelfVariableAsInt(serverConnectionHandlerID, CLIENT_FLAG_TALKING, &talkStatus)) != ERROR_ok) {
  536.                 printf("Error querying own client talk status: %d\n", error);
  537.                 break;
  538.             }
  539.         } else {
  540.             if((error = ts3client_getClientVariableAsInt(serverConnectionHandlerID, ids[i], CLIENT_FLAG_TALKING, &talkStatus)) != ERROR_ok) {
  541.                 printf("Error querying client talk status: %d\n", error);
  542.                 break;
  543.             }
  544.         }
  545.  
  546.         printf("%u - %s (%stalking)\n", ids[i], name, (talkStatus == STATUS_TALKING ? "" : "not "));
  547.         ts3client_freeMemory(name);
  548.     }
  549.     printf("\n");
  550.  
  551.     ts3client_freeMemory(ids);  /* Release array */
  552. }
  553.  
  554. /*
  555.  * Print all visible clients on the given virtual server
  556.  */
  557. void showClients(uint64 serverConnectionHandlerID) {
  558.     anyID *ids;
  559.     anyID ownClientID;
  560.     int i;
  561.     unsigned int error;
  562.  
  563.     printf("\nList of all visible clients on virtual server %llu:\n", (unsigned long long)serverConnectionHandlerID);
  564.     if((error = ts3client_getClientList(serverConnectionHandlerID, &ids)) != ERROR_ok) {  /* Get array of client IDs */
  565.         printf("Error getting client list: %d\n", error);
  566.         return;
  567.     }
  568.     if(!ids[0]) {
  569.         printf("No clients\n\n");
  570.         ts3client_freeMemory(ids);
  571.         return;
  572.     }
  573.  
  574.     /* Get own clientID as we need to call CLIENT_FLAG_TALKING with getClientSelfVariable for own client */
  575.     if((error = ts3client_getClientID(serverConnectionHandlerID, &ownClientID)) != ERROR_ok) {
  576.         printf("Error querying own client ID: %d\n", error);
  577.         return;
  578.     }
  579.  
  580.     for(i=0; ids[i]; i++) {
  581.         char* name;
  582.         int talkStatus;
  583.  
  584.         if((error = ts3client_getClientVariableAsString(serverConnectionHandlerID, ids[i], CLIENT_NICKNAME, &name)) != ERROR_ok) {  /* Query client nickname... */
  585.             printf("Error querying client nickname: %d\n", error);
  586.             break;
  587.         }
  588.  
  589.         if(ids[i] == ownClientID) {  /* CLIENT_FLAG_TALKING must be queried with getClientSelfVariable for own client */
  590.             if((error = ts3client_getClientSelfVariableAsInt(serverConnectionHandlerID, CLIENT_FLAG_TALKING, &talkStatus)) != ERROR_ok) {
  591.                 printf("Error querying own client talk status: %d\n", error);
  592.                 break;
  593.             }
  594.         } else {
  595.             if((error = ts3client_getClientVariableAsInt(serverConnectionHandlerID, ids[i], CLIENT_FLAG_TALKING, &talkStatus)) != ERROR_ok) {
  596.                 printf("Error querying client talk status: %d\n", error);
  597.                 break;
  598.             }
  599.         }
  600.  
  601.         printf("%u - %s (%stalking)\n", ids[i], name, (talkStatus == STATUS_TALKING ? "" : "not "));
  602.         ts3client_freeMemory(name);
  603.     }
  604.     printf("\n");
  605.  
  606.     ts3client_freeMemory(ids);  /* Release array */
  607. }
  608.  
  609. void emptyInputBuffer() {
  610.     int c;
  611.     while((c = getchar()) != '\n' && c != EOF);
  612. }
  613.  
  614. uint64 enterChannelID() {
  615.     uint64 channelID;
  616.     int n;
  617.  
  618.     printf("\nEnter channel ID: ");
  619.     n = scanf("%llu", (unsigned long long*)&channelID);
  620.     emptyInputBuffer();
  621.     if(n == 0) {
  622.         printf("Invalid input. Please enter a number.\n\n");
  623.         return 0;
  624.     }
  625.     return channelID;
  626. }
  627.  
  628. void createDefaultChannelName(char *name) {
  629.     static int i = 1;
  630.     sprintf(name, "Channel_%d", i++);
  631. }
  632.  
  633. void enterName(char *name) {
  634.     char *s;
  635.     printf("\nEnter name: ");
  636.     fgets(name, NAME_BUFSIZE, stdin);
  637.     s = strrchr(name, '\n');
  638.     if(s) {
  639.         *s = '\0';
  640.     }
  641. }
  642.  
  643. void enterPassword(char *password) {
  644.     char *s;
  645.     printf("\nEnter password: ");
  646.     fgets(password, CHANNEL_PASSWORD_BUFSIZE, stdin);
  647.     s = strrchr(password, '\n');
  648.     if(s) {
  649.         *s = '\0';
  650.     }
  651. }
  652.  
  653. void createChannel(uint64 serverConnectionHandlerID, const char *name, const char* password) {
  654.     unsigned int error;
  655.  
  656.     /* Set data of new channel. Use channelID of 0 for creating channels. */
  657.     CHECK_ERROR(ts3client_setChannelVariableAsString(serverConnectionHandlerID, 0, CHANNEL_NAME,                name));
  658.     CHECK_ERROR(ts3client_setChannelVariableAsString(serverConnectionHandlerID, 0, CHANNEL_TOPIC,               "Test channel topic"));
  659.     CHECK_ERROR(ts3client_setChannelVariableAsString(serverConnectionHandlerID, 0, CHANNEL_DESCRIPTION,         "Test channel description"));
  660.     CHECK_ERROR(ts3client_setChannelVariableAsInt   (serverConnectionHandlerID, 0, CHANNEL_FLAG_PERMANENT,      1));
  661.     CHECK_ERROR(ts3client_setChannelVariableAsInt   (serverConnectionHandlerID, 0, CHANNEL_FLAG_SEMI_PERMANENT, 0));
  662.  
  663.     if(password && *password){
  664.         CHECK_ERROR(ts3client_setChannelVariableAsString(serverConnectionHandlerID, 0, CHANNEL_PASSWORD, password));
  665.     }
  666.  
  667.     /* Flush changes to server */
  668.     CHECK_ERROR(ts3client_flushChannelCreation(serverConnectionHandlerID, 0, NULL));
  669.  
  670.     printf("\nCreated channel\n\n");
  671.     return;
  672.  
  673. on_error:
  674.     printf("\nError creating channel: %d\n\n", error);
  675. }
  676.  
  677. void deleteChannel(uint64 serverConnectionHandlerID) {
  678.     uint64 channelID;
  679.     unsigned int error;
  680.  
  681.     /* Query channel ID from user */
  682.     channelID = enterChannelID();
  683.  
  684.     /* Delete channel */
  685.     if((error = ts3client_requestChannelDelete(serverConnectionHandlerID, channelID, 0, NULL)) == ERROR_ok) {
  686.         printf("Deleted channel %llu\n\n", (unsigned long long)channelID);
  687.     } else {
  688.         char* errormsg;
  689.         if(ts3client_getErrorMessage(error, &errormsg) == ERROR_ok) {
  690.             printf("Error requesting channel delete: %s (%d)\n\n", errormsg, error);
  691.             ts3client_freeMemory(errormsg);
  692.         }
  693.     }
  694. }
  695.  
  696. void renameChannel(uint64 serverConnectionHandlerID) {
  697.     uint64 channelID;
  698.     unsigned int error;
  699.     char name[NAME_BUFSIZE];
  700.  
  701.     /* Query channel ID from user */
  702.     channelID = enterChannelID();
  703.  
  704.     /* Query new channel name from user */
  705.     enterName(name);
  706.  
  707.     /* Change channel name and flush changes */
  708.     CHECK_ERROR(ts3client_setChannelVariableAsString(serverConnectionHandlerID, channelID, CHANNEL_NAME, name));
  709.     CHECK_ERROR(ts3client_flushChannelUpdates(serverConnectionHandlerID, channelID, NULL));
  710.  
  711.     printf("Renamed channel %llu\n\n", (unsigned long long)channelID);
  712.     return;
  713.  
  714. on_error:
  715.     printf("Error renaming channel: %d\n\n", error);
  716. }
  717.  
  718. void switchChannel(uint64 serverConnectionHandlerID) {
  719.     unsigned int error;
  720.     char password[CHANNEL_PASSWORD_BUFSIZE];
  721. #ifndef CUSTOM_PASSWORDS
  722.     int hasPassword;
  723. #endif
  724.  
  725.     /* Query channel ID from user */
  726.     uint64 channelID = enterChannelID();
  727.  
  728.     /* Query own client ID */
  729.     anyID clientID;
  730.     if((error = ts3client_getClientID(serverConnectionHandlerID, &clientID)) != ERROR_ok) {
  731.         printf("Error querying own client ID: %d\n", error);
  732.         return;
  733.     }
  734.  
  735. #ifndef CUSTOM_PASSWORDS
  736.     /* Using standard password mechanism */
  737.  
  738.     /* Check if channel has a password set */
  739.     if((error = ts3client_getChannelVariableAsInt(serverConnectionHandlerID, channelID, CHANNEL_FLAG_PASSWORD, &hasPassword)) != ERROR_ok) {
  740.         printf("Failed to get password flag: %d\n", error);
  741.         return;
  742.     }
  743.  
  744.     /* Get channel password if channel is password protected */
  745.     if(hasPassword) {
  746.         enterPassword(password);
  747.     } else {
  748.         password[0] = '\0';
  749.     }
  750. #else
  751.     /* Using custom password mechanism, always ask user for password */
  752.     enterPassword(password);
  753. #endif
  754.  
  755.     /* Request moving own client into given channel */
  756.     if((error = ts3client_requestClientMove(serverConnectionHandlerID, clientID, channelID, password, NULL)) != ERROR_ok) {
  757.         printf("Error moving client into channel channel: %d\n", error);
  758.         return;
  759.     }
  760.     printf("Switching into channel %llu\n\n", (unsigned long long)channelID);
  761. }
  762.  
  763. void toggleVAD(uint64 serverConnectionHandlerID) {
  764.     static short b = 1;
  765.     unsigned int error;
  766.  
  767.     /* Adjust "vad" preprocessor value */
  768.     if((error = ts3client_setPreProcessorConfigValue(serverConnectionHandlerID, "vad", b ? "false" : "true")) != ERROR_ok) {
  769.         printf("Error toggling VAD: %d\n", error);
  770.         return;
  771.     }
  772.     b = !b;
  773.     printf("\nToggled VAD %s.\n\n", b ? "on" : "off");
  774. }
  775.  
  776. void setVadLevel(uint64 serverConnectionHandlerID) {
  777.     int vad, n;
  778.     unsigned int error;
  779.     char s[100];
  780.  
  781.     printf("\nEnter VAD level: ");
  782.     n = scanf("%d", &vad);
  783.     emptyInputBuffer();
  784.     if(n == 0) {
  785.         printf("Invalid input. Please enter a number.\n\n");
  786.         return;
  787.     }
  788.  
  789.     /* Adjust "voiceactivation_level" preprocessor value */
  790.     snprintf(s, 100, "%d", vad);
  791.     if((error = ts3client_setPreProcessorConfigValue(serverConnectionHandlerID, "voiceactivation_level", s)) != ERROR_ok) {
  792.         printf("Error setting VAD level: %d\n", error);
  793.         return;
  794.     }
  795.     printf("\nSet VAD level to %s.\n\n", s);
  796. }
  797.  
  798. void requestWhisperList(uint64 serverConnectionHandlerID) {
  799.     int n;
  800.     anyID clientID;
  801.     uint64 targetID;
  802.     unsigned int error;
  803.     uint64 targetChannels[2];
  804.  
  805.     printf("\nEnter ID of the client whose whisper list should be modified (0 for own client): ");
  806.     n = scanf("%hu", &clientID);
  807.     emptyInputBuffer();
  808.     if(n == 0) {
  809.         printf("Invalid input. Please enter a number.\n\n");
  810.         return;
  811.     }
  812.  
  813.     printf("\nEnter target channel ID: ");
  814.     n = scanf("%llu", (unsigned long long*)&targetID);
  815.     emptyInputBuffer();
  816.     if(n == 0) {
  817.         printf("Invalid input. Please enter a number.\n\n");
  818.         return;
  819.     }
  820.  
  821.     targetChannels[0] = targetID;
  822.     targetChannels[1] = 0;
  823.  
  824.     if((error = ts3client_requestClientSetWhisperList(serverConnectionHandlerID, clientID, targetChannels, NULL, NULL)) != ERROR_ok) {
  825.         char* errormsg;
  826.         if(ts3client_getErrorMessage(error, &errormsg) == ERROR_ok) {
  827.             printf("Error requesting whisperlist: %s\n", errormsg);
  828.             ts3client_freeMemory(errormsg);
  829.         }
  830.         return;
  831.     }
  832.     printf("Whisper list requested for client %d in channel %llu\n", clientID, (unsigned long long)targetID);
  833. }
  834.  
  835. void requestClearWhisperList(uint64 serverConnectionHandlerID) {
  836.     int n;
  837.     anyID clientID;
  838.     unsigned int error;
  839.  
  840.     printf("\nEnter client ID: ");
  841.     printf("\nEnter ID of the client whose whisper list should be cleared (0 for own client): ");
  842.     n = scanf("%hu", &clientID);
  843.     emptyInputBuffer();
  844.     if(n == 0) {
  845.         printf("Invalid input. Please enter a number.\n\n");
  846.         return;
  847.     }
  848.  
  849.     if((error = ts3client_requestClientSetWhisperList(serverConnectionHandlerID, clientID, NULL, NULL, NULL)) != ERROR_ok) {
  850.         char* errormsg;
  851.         if(ts3client_getErrorMessage(error, &errormsg) == ERROR_ok) {
  852.             printf("Error clearing whisperlist: %s\n", errormsg);
  853.             ts3client_freeMemory(errormsg);
  854.         }
  855.         return;
  856.     }
  857.     printf("Whisper list cleared for client %u\n", clientID);
  858. }
  859.  
  860. int initLocalTestMode() {
  861.     unsigned int error;
  862.  
  863.     /* spawn a new server connection handler used as local loopback device */
  864.     if((error = ts3client_spawnNewServerConnectionHandler(0, &vadTestscHandlerID)) != ERROR_ok) {
  865.         printf("Error spawning server connection handler: %d\n", error);
  866.         vadTestscHandlerID = 0;
  867.         return 1;
  868.     }
  869.  
  870.     /* Open default capture device for the new server connection handler */
  871.     if((error = ts3client_openCaptureDevice(vadTestscHandlerID, "", "")) != ERROR_ok) {
  872.         printf("Error opening capture device: %d\n", error);
  873.         return 1;
  874.     }
  875.  
  876.     /* Open default playback device for the new server connection handler */
  877.     if((error = ts3client_openPlaybackDevice(vadTestscHandlerID, "", "")) != ERROR_ok) {
  878.         printf("Error opening playback device: %d\n", error);
  879.         return 1;
  880.     }
  881.  
  882.     /* Set the server connection handler as a local loopback device, so we can hear our own voice without connecting to a server. */
  883.     /* The original capture device for the current server is automatically deactivated. */
  884.     if((error = ts3client_setLocalTestMode(vadTestscHandlerID, 1)) != ERROR_ok){
  885.         printf("Error setting local test mode\n");
  886.         return 1;
  887.     }
  888.  
  889.     return 0;
  890. }
  891.  
  892. void destroyLocalTestMode(uint64 scHandlerID){
  893.     unsigned int error;
  894.  
  895.     /* Close playback device */
  896.     if((ts3client_closePlaybackDevice(scHandlerID)) != ERROR_ok){
  897.         printf("Unable to close playback device\n");
  898.     }
  899.     /* Close capture device */
  900.     if((ts3client_closeCaptureDevice(scHandlerID)) != ERROR_ok) {
  901.         printf("Unable to close capture device\n");
  902.     }
  903.     /* Unset local test mode */
  904.     if((error = ts3client_setLocalTestMode(scHandlerID, 0)) != ERROR_ok) {
  905.         printf("Unable to stop local test mode\n");
  906.     }
  907.     /* Destroy schandlerid */
  908.     if((error = ts3client_destroyServerConnectionHandler(scHandlerID)) != ERROR_ok){
  909.         printf("Unable to destroy scHandler\n");
  910.     }
  911.  
  912.     /* After closing the local loopback device, reactivate the microphone on our current server connection. */
  913.     if((error = ts3client_activateCaptureDevice(DEFAULT_VIRTUAL_SERVER)) != ERROR_ok){
  914.         printf("unable to reactivate capture device\n");
  915.     }
  916. }
  917.  
  918. void printVadLevel() {
  919.     unsigned int error;
  920.     float result;
  921.  
  922.     if((error = ts3client_getPreProcessorInfoValueFloat(vadTestscHandlerID, "decibel_last_period", &result)) != ERROR_ok) {
  923.         printf("Error getting vad level\n");
  924.     }
  925.     printf("%.2f - %s", result, (vadTestTalkStatus == STATUS_TALKING ? "talking" : "not talking"));
  926.     printf("\n");
  927. }
  928.  
  929. /* Set the microphone voice activation detection level */
  930. void configureMicrophone() {
  931.     unsigned int error;
  932.     int counter = 0;
  933.  
  934.     /* Enable local loopback device */
  935.     if(initLocalTestMode() != 0) {
  936.         return;
  937.     }
  938.  
  939.     /* Local loopback device is setup, now enter loop where the user can change the voice activation level while once per second the
  940.      * current volume level is printed. */
  941.     printf("\n**********************************\n");
  942.     printf("Entering configure microphone mode\n");
  943.     printf("[v] - set VAD level\n");
  944.     printf("[q] - quit microphone configuration\n\n");
  945.  
  946.     for(;;) {
  947. #ifdef _WIN32
  948.         if(_kbhit()) {
  949.             int c = _getche();
  950. #else
  951.             { int c = getc(stdin);  // No kbhit on posix
  952. #endif
  953.             switch(c) {
  954.                 case 'v': {
  955.                     int n;
  956.                     float inputVadLevel;
  957.                     char vad[128];
  958.  
  959.                     printf("Insert value to change voice activations level\n");
  960.                     n = scanf("%f", &inputVadLevel);
  961.                     emptyInputBuffer();
  962.                     if(n == 0) {
  963.                         printf("Invalid input. Please enter a number.\n\n");
  964.                         continue;
  965.                     }
  966.                     sprintf(vad, "%f", inputVadLevel);
  967.  
  968.                     if((error = ts3client_setPreProcessorConfigValue(vadTestscHandlerID, "voiceactivation_level", vad)) != ERROR_ok) {
  969.                         printf("unable to set vad value\n");
  970.                         continue;
  971.                     }
  972.                     printf("new vad level: %s\n", vad);
  973.                     continue;
  974.                 }
  975.                 case 'q':
  976.                     destroyLocalTestMode(vadTestscHandlerID);
  977.                     printf("\n**********************************\n");
  978.                     printf("Left configure microphone mode\n\n");
  979.                     vadTestscHandlerID = 0;
  980.                     return;
  981.             }
  982.         }
  983.  
  984. #ifdef _WIN32  /* On Windows we print this once per second, on Unix only on each Return keyboard input due to lack of easy kbhit replacement on Unix */
  985.         if(++counter > 9)
  986. #endif
  987.         {
  988.             printVadLevel();
  989.             counter = 0;
  990.         }
  991.  
  992.         SLEEP(100);
  993.     }
  994. }
  995.  
  996. void toggleRecordSound(uint64 serverConnectionHandlerID){
  997.     unsigned int error;
  998.  
  999.     if (!recordSound){
  1000.         recordSound = 1;
  1001.         if((error = ts3client_startVoiceRecording(serverConnectionHandlerID)) != ERROR_ok){
  1002.             char* errormsg;
  1003.             if(ts3client_getErrorMessage(error, &errormsg) == ERROR_ok) {
  1004.                 printf("Error notifying server of startVoiceRecording: %s\n", errormsg);
  1005.                 ts3client_freeMemory(errormsg);
  1006.                 return;
  1007.             }
  1008.         }
  1009.         printf("Started recording sound to wav\n");
  1010.     } else {
  1011.         recordSound = 0;
  1012.         if((error = ts3client_stopVoiceRecording(serverConnectionHandlerID)) != ERROR_ok){
  1013.             char* errormsg;
  1014.             if(ts3client_getErrorMessage(error, &errormsg) == ERROR_ok) {
  1015.                 printf("Error notifying server of stopVoiceRecording: %s\n", errormsg);
  1016.                 ts3client_freeMemory(errormsg);
  1017.                 return;
  1018.             }
  1019.         }
  1020.         printf("Stopped recording sound to wav\n");
  1021.     }
  1022. }
  1023.  
  1024. int readIdentity(char* identity) {
  1025.     FILE *file;
  1026.  
  1027.     if((file = fopen("identity.txt", "r")) == NULL) {
  1028.         printf("Could not open file 'identity.txt' for reading.\n");
  1029.         return -1;
  1030.     }
  1031.  
  1032.     fgets(identity, IDENTITY_BUFSIZE, file);
  1033.     if(ferror(file) != 0) {
  1034.         fclose (file);
  1035.         printf("Error reading identity from file 'identity.txt'.\n");
  1036.         return -1;
  1037.     }
  1038.     fclose (file);
  1039.     return 0;
  1040. }
  1041.  
  1042. int writeIdentity(const char* identity) {
  1043.     FILE *file;
  1044.  
  1045.     if((file = fopen("identity.txt", "w")) == NULL) {
  1046.         printf("Could not open file 'identity.txt' for writing.\n");
  1047.         return -1;
  1048.     }
  1049.  
  1050.     fputs(identity, file);
  1051.     if(ferror(file) != 0) {
  1052.         fclose (file);
  1053.         printf("Error writing identity to file 'identity.txt'.\n");
  1054.         return -1;
  1055.     }
  1056.     fclose (file);
  1057.     return 0;
  1058. }
  1059.  
  1060. void showHelp() {
  1061.     printf("\n[q] - Disconnect from server\n[h] - Show this help\n[c] - Show channels\n[s] - Switch to specified channel\n");
  1062.     printf("[l] - Show all visible clients\n[L] - Show all clients in specific channel\n[n] - Create new channel with generated name\n[N] - Create new channel with custom name\n");
  1063.     printf("[d] - Delete channel\n[r] - Rename channel\n[R] - Record sound to wav\n[v] - Toggle Voice Activity Detection / Continuous transmission \n[V] - Set Voice Activity Detection level\n");
  1064.     printf("[w] - Set whisper list\n[W] - Clear whisper list\n[m] - Configure microphone\n\n");
  1065. }
  1066.  
  1067. char* programPath(char* programInvocation){
  1068.     char* path;
  1069.     char* end;
  1070.     int length;
  1071.     char pathsep;
  1072.  
  1073.     if (programInvocation == NULL) return strdup("");
  1074.  
  1075. #ifdef _WIN32
  1076.     pathsep = '\\';
  1077. #else
  1078.     pathsep = '/';
  1079. #endif
  1080.  
  1081.     end = strrchr(programInvocation, pathsep);
  1082.     if (!end) return strdup("");
  1083.  
  1084.     length = (end - programInvocation) + 2;
  1085.     path = (char*)malloc(length);
  1086.     strncpy(path, programInvocation, length - 1);
  1087.     path[length - 1] = 0;
  1088.  
  1089.     return path;
  1090. }
  1091.  
  1092. int main(int argc, char** argv) {
  1093.     uint64 scHandlerID;
  1094.     unsigned int error;
  1095.     char* mode;
  1096.     char** device;
  1097.     char *version;
  1098.     char identity[IDENTITY_BUFSIZE];
  1099.     short abort = 0;
  1100.     char* path;
  1101.  
  1102.     /* Create struct for callback function pointers */
  1103.     struct ClientUIFunctions funcs;
  1104.  
  1105.     /* Initialize all callbacks with NULL */
  1106.     memset(&funcs, 0, sizeof(struct ClientUIFunctions));
  1107.  
  1108.     /* Callback function pointers */
  1109.     /* It is sufficient to only assign those callback functions you are using. When adding more callbacks, add those function pointers here. */
  1110.     funcs.onConnectStatusChangeEvent        = onConnectStatusChangeEvent;
  1111.     funcs.onNewChannelEvent                 = onNewChannelEvent;
  1112.     funcs.onNewChannelCreatedEvent          = onNewChannelCreatedEvent;
  1113.     funcs.onDelChannelEvent                 = onDelChannelEvent;
  1114.     funcs.onClientMoveEvent                 = onClientMoveEvent;
  1115.     funcs.onClientMoveSubscriptionEvent     = onClientMoveSubscriptionEvent;
  1116.     funcs.onClientMoveTimeoutEvent          = onClientMoveTimeoutEvent;
  1117.     funcs.onTalkStatusChangeEvent           = onTalkStatusChangeEvent;
  1118.     funcs.onIgnoredWhisperEvent             = onIgnoredWhisperEvent;
  1119.     funcs.onServerErrorEvent                = onServerErrorEvent;
  1120.     funcs.onUserLoggingMessageEvent         = onUserLoggingMessageEvent;
  1121.     funcs.onCustomPacketEncryptEvent        = onCustomPacketEncryptEvent;
  1122.     funcs.onCustomPacketDecryptEvent        = onCustomPacketDecryptEvent;
  1123.     funcs.onEditMixedPlaybackVoiceDataEvent = onEditMixedPlaybackVoiceDataEvent;
  1124. #ifdef CUSTOM_PASSWORDS
  1125.     funcs.onClientPasswordEncrypt           = onClientPasswordEncrypt;
  1126. #endif
  1127.  
  1128.     /* Initialize client lib with callbacks */
  1129.     /* Resource path points to the SDK\bin directory to locate the soundbackends folder when running from Visual Studio. */
  1130.     /* If you want to run directly from the SDK\bin directory, use an empty string instead to locate the soundbackends folder in the current directory. */
  1131.     path = programPath(argv[0]);
  1132.     if((error = ts3client_initClientLib(&funcs, NULL, LogType_FILE | LogType_CONSOLE | LogType_USERLOGGING, NULL, path)) != ERROR_ok) {
  1133.         char* errormsg;
  1134.         if(ts3client_getErrorMessage(error, &errormsg) == ERROR_ok) {
  1135.             printf("Error initialzing serverlib: %s\n", errormsg);
  1136.             ts3client_freeMemory(errormsg);
  1137.         }
  1138.         return 1;
  1139.     }
  1140.  
  1141.     /* Spawn a new server connection handler using the default port and store the server ID */
  1142.     if((error = ts3client_spawnNewServerConnectionHandler(0, &scHandlerID)) != ERROR_ok) {
  1143.         printf("Error spawning server connection handler: %d\n", error);
  1144.         return 1;
  1145.     }
  1146.  
  1147.     /* Get default capture mode */
  1148.     if((error = ts3client_getDefaultCaptureMode(&mode)) != ERROR_ok) {
  1149.         printf("Error getting default capture mode: %d\n", error);
  1150.         return 1;
  1151.     }
  1152.     printf("Default capture mode: %s\n", mode);
  1153.  
  1154.     /* Get default capture device */
  1155.     if((error = ts3client_getDefaultCaptureDevice(mode, &device)) != ERROR_ok) {
  1156.         printf("Error getting default capture device: %d\n", error);
  1157.         return 1;
  1158.     }
  1159.     printf("Default capture device: %s %s\n", device[0], device[1]);
  1160.  
  1161.     /* Open default capture device */
  1162.     /* Instead of passing mode and device[1], it would also be possible to pass empty strings to open the default device */
  1163.     if((error = ts3client_openCaptureDevice(scHandlerID, mode, device[1])) != ERROR_ok) {
  1164.         printf("Error opening capture device: %d\n", error);
  1165.     }
  1166.  
  1167.     /* Get default playback mode */
  1168.     if((error = ts3client_getDefaultPlayBackMode(&mode)) != ERROR_ok) {
  1169.         printf("Error getting default playback mode: %d\n", error);
  1170.         return 1;
  1171.     }
  1172.     printf("Default playback mode: %s\n", mode);
  1173.  
  1174.     /* Get default playback device */
  1175.     if((error = ts3client_getDefaultPlaybackDevice(mode, &device)) != ERROR_ok) {
  1176.         printf("Error getting default playback device: %d\n", error);
  1177.         return 1;
  1178.     }
  1179.     printf("Default playback device: %s %s\n", device[0], device[1]);
  1180.  
  1181.     /* Open default playback device */
  1182.     /* Instead of passing mode and device[1], it would also be possible to pass empty strings to open the default device */
  1183.     if((error = ts3client_openPlaybackDevice(scHandlerID, mode, device[1])) != ERROR_ok) {
  1184.         printf("Error opening playback device: %d\n", error);
  1185.     }
  1186.  
  1187.     /* Try reading identity from file, otherwise create new identity */
  1188.     if(readIdentity(identity) != 0) {
  1189.         char* id;
  1190.         if((error = ts3client_createIdentity(&id)) != ERROR_ok) {
  1191.             printf("Error creating identity: %d\n", error);
  1192.             return 0;
  1193.         }
  1194.         if(strlen(id) >= IDENTITY_BUFSIZE) {
  1195.             printf("Not enough bufsize for identity string\n");
  1196.             return 0;
  1197.         }
  1198.         strcpy(identity, id);
  1199.         ts3client_freeMemory(id);
  1200.         writeIdentity(identity);
  1201.     }
  1202.     printf("Using identity: %s\n", identity);
  1203.  
  1204.     /* Connect to server on localhost:9987 with nickname "client", no default channel, no default channel password and server password "secret" */
  1205.     if((error = ts3client_startConnection(scHandlerID, identity, "localhost", 9987, "client", NULL, "", "secret")) != ERROR_ok) {
  1206.         printf("Error connecting to server: %d\n", error);
  1207.         return 1;
  1208.     }
  1209.  
  1210.     printf("Client lib initialized and running\n");
  1211.  
  1212.     /* Query and print client lib version */
  1213.     if((error = ts3client_getClientLibVersion(&version)) != ERROR_ok) {
  1214.         printf("Failed to get clientlib version: %d\n", error);
  1215.         return 1;
  1216.     }
  1217.     printf("Client lib version: %s\n", version);
  1218.     ts3client_freeMemory(version);  /* Release dynamically allocated memory */
  1219.     version = NULL;
  1220.  
  1221.     SLEEP(300);
  1222.  
  1223.     /* Simple commandline interface */
  1224.     printf("\nTeamSpeak 3 client commandline interface\n");
  1225.     showHelp();
  1226.  
  1227.     while(!abort) {
  1228.         int c = getc(stdin);
  1229.         switch(c) {
  1230.             case 'q':
  1231.                 printf("\nDisconnecting from server...\n");
  1232.                 abort = 1;
  1233.                 break;
  1234.             case 'h':
  1235.                 showHelp();
  1236.                 break;
  1237.             case 'c':
  1238.                 showChannels(DEFAULT_VIRTUAL_SERVER);
  1239.                 break;
  1240.             case 'l':
  1241.                 showClients(DEFAULT_VIRTUAL_SERVER);
  1242.                 break;
  1243.             case 'L':
  1244.             {
  1245.                 uint64 channelID = enterChannelID();
  1246.                 if(channelID > 0)
  1247.                     showChannelClients(DEFAULT_VIRTUAL_SERVER, channelID);
  1248.                 break;
  1249.             }
  1250.             case 'n':
  1251.             {
  1252.                 char name[NAME_BUFSIZE];
  1253.                 createDefaultChannelName(name);
  1254.                 createChannel(DEFAULT_VIRTUAL_SERVER, name, NULL);
  1255.                 break;
  1256.             }
  1257.             case 'N':
  1258.             {
  1259.                 char name[NAME_BUFSIZE];
  1260.                 char password[CHANNEL_PASSWORD_BUFSIZE];
  1261.                 emptyInputBuffer();
  1262.                 enterName(name);
  1263.                 enterPassword(password);
  1264.                 createChannel(DEFAULT_VIRTUAL_SERVER, name, password);
  1265.                 break;
  1266.             }
  1267.             case 'd':
  1268.                 deleteChannel(DEFAULT_VIRTUAL_SERVER);
  1269.                 break;
  1270.             case 'r':
  1271.                 renameChannel(DEFAULT_VIRTUAL_SERVER);
  1272.                 break;
  1273.             case 'R':
  1274.                 toggleRecordSound(DEFAULT_VIRTUAL_SERVER);
  1275.                 break;
  1276.             case 's':
  1277.                 switchChannel(DEFAULT_VIRTUAL_SERVER);
  1278.                 break;
  1279.             case 'v':
  1280.                 toggleVAD(DEFAULT_VIRTUAL_SERVER);
  1281.                 break;
  1282.             case 'V':
  1283.                 setVadLevel(DEFAULT_VIRTUAL_SERVER);
  1284.                 break;
  1285.             case 'w':
  1286.                 requestWhisperList(DEFAULT_VIRTUAL_SERVER);
  1287.                 break;
  1288.             case 'W':
  1289.                 requestClearWhisperList(DEFAULT_VIRTUAL_SERVER);
  1290.                 break;
  1291.             case 'm':
  1292.                 configureMicrophone();
  1293.                 showHelp();  /* Display main menu after leaving configure microphone mode */
  1294.         }
  1295.  
  1296.         SLEEP(50);
  1297.     }
  1298.  
  1299.     /* Disconnect from server */
  1300.     if((error = ts3client_stopConnection(scHandlerID, "leaving")) != ERROR_ok) {
  1301.         printf("Error stopping connection: %d\n", error);
  1302.         return 1;
  1303.     }
  1304.  
  1305.     SLEEP(200);
  1306.  
  1307.     /* Destroy server connection handler */
  1308.     if((error = ts3client_destroyServerConnectionHandler(scHandlerID)) != ERROR_ok) {
  1309.         printf("Error destroying clientlib: %d\n", error);
  1310.         return 1;
  1311.     }
  1312.  
  1313.     /* Shutdown client lib */
  1314.     if((error = ts3client_destroyClientLib()) != ERROR_ok) {
  1315.         printf("Failed to destroy clientlib: %d\n", error);
  1316.         return 1;
  1317.     }
  1318.  
  1319.     /* This is a small hack, to close an open recording sound file */
  1320.     recordSound = 0;
  1321.     onEditMixedPlaybackVoiceDataEvent(DEFAULT_VIRTUAL_SERVER, NULL, 0, 0, NULL, NULL);
  1322.  
  1323.     return 0;
  1324. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement