forked from BearWare/TeamTalk5
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTeamTalk5.py
More file actions
1801 lines (1583 loc) · 71.4 KB
/
TeamTalk5.py
File metadata and controls
1801 lines (1583 loc) · 71.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Copyright (c) 2005-2018, BearWare.dk
#
# Contact Information:
#
# Bjoern D. Rasmussen
# Kirketoften 5
# DK-8260 Viby J
# Denmark
# Email: contact@bearware.dk
# Phone: +45 20 20 54 59
# Web: http://www.bearware.dk
#
# This source code is part of the TeamTalk SDK owned by
# BearWare.dk. Use of this file, or its compiled unit, requires a
# TeamTalk SDK License Key issued by BearWare.dk.
#
# The TeamTalk SDK License Agreement along with its Terms and
# Conditions are outlined in the file License.txt included with the
# TeamTalk SDK distribution.
import sys
import os
import ctypes
from ctypes import cdll, c_int, c_char, c_wchar, c_wchar_p, c_char_p, \
c_longlong, c_uint, c_float, c_void_p, c_uint16, \
Structure, Union, POINTER, byref
if sys.platform == "win32":
if (sys.version_info.major == 3 and sys.version_info.minor >= 8):
os.add_dll_directory(os.getcwd())
# Path relative to TeamTalk SDK's DLL location
os.add_dll_directory(os.path.dirname(os.path.abspath(__file__)) + "\\..\\TeamTalk_DLL")
dll = cdll.TeamTalk5
TTCHAR = c_wchar
TTCHAR_P = c_wchar_p
from ctypes.wintypes import BOOL
elif sys.platform == "darwin":
# Darwin is not supported. Seems SIP is preventing this from
# working. Setting DYLD_LIBRARY_PATH doesn't help.
dll = cdll.LoadLibrary("libTeamTalk5.dylib")
TTCHAR = c_char
TTCHAR_P = c_char_p
BOOL = c_int
else:
dll = cdll.LoadLibrary("libTeamTalk5.so")
TTCHAR = c_char
TTCHAR_P = c_char_p
BOOL = c_int
INT32 = c_int
INT64 = c_longlong
UINT32 = c_uint
FLOAT = c_float
TT_STRLEN = 512
TT_VIDEOFORMATS_MAX = 1024
TT_TRANSMITUSERS_MAX = 128
TT_CHANNELS_OPERATOR_MAX = 16
TT_TRANSMITQUEUE_MAX = 16
TT_SAMPLERATES_MAX = 16
_TTInstance = c_void_p
_TTSoundLoop = c_void_p
# Encode string to UTF-8. Encoding on Windows is not necessary since
# string to and from TeamTalk5.dll are UTF-16.
def ttstr(ttchar_p_str: TTCHAR_P) -> str:
if sys.platform == "win32":
return ttchar_p_str
if isinstance(ttchar_p_str, bytes):
return str(ttchar_p_str, encoding = 'utf-8')
if isinstance(ttchar_p_str, str):
return ttchar_p_str.encode('utf-8')
return ttchar_p_str
# bindings
class StreamType(UINT32):
STREAMTYPE_NONE = 0x00000000
STREAMTYPE_VOICE = 0x00000001
STREAMTYPE_VIDEOCAPTURE = 0x00000002
STREAMTYPE_MEDIAFILE_AUDIO = 0x00000004
STREAMTYPE_MEDIAFILE_VIDEO = 0x00000008
STREAMTYPE_DESKTOP = 0x00000010
STREAMTYPE_DESKTOPINPUT = 0x00000020
STREAMTYPE_MEDIAFILE = STREAMTYPE_MEDIAFILE_AUDIO | STREAMTYPE_MEDIAFILE_VIDEO
STREAMTYPE_CHANNELMSG = 0x00000040
STREAMTYPE_LOCALMEDIAPLAYBACK_AUDIO = 0x00000080
STREAMTYPE_CLASSROOM_ALL = STREAMTYPE_VOICE | STREAMTYPE_VIDEOCAPTURE | STREAMTYPE_DESKTOP | STREAMTYPE_MEDIAFILE | STREAMTYPE_CHANNELMSG
class SoundSystem(INT32):
SOUNDSYSTEM_NONE = 0
SOUNDSYSTEM_WINMM = 1
SOUNDSYSTEM_DSOUND = 2
SOUNDSYSTEM_ALSA = 3
SOUNDSYSTEM_COREAUDIO = 4
SOUNDSYSTEM_WASAPI = 5
SOUNDSYSTEM_OPENSLES_ANDROID = 7
SOUNDSYSTEM_AUDIOUNIT = 8
SOUNDSYSTEM_PULSEAUDIO = 10
class SoundDeviceFeature(UINT32):
SOUNDDEVICEFEATURE_NONE = 0x0000
SOUNDDEVICEFEATURE_AEC = 0x0001
SOUNDDEVICEFEATURE_AGC = 0x0002
SOUNDDEVICEFEATURE_DENOISE = 0x0004
SOUNDDEVICEFEATURE_3DPOSITION = 0x0008
SOUNDDEVICEFEATURE_DUPLEXMODE = 0x0010
SOUNDDEVICEFEATURE_DEFAULTCOMDEVICE = 0x0020
class SoundDevice(Structure):
_fields_ = [
("nDeviceID", INT32),
("nSoundSystem", INT32),
("szDeviceName", TTCHAR*TT_STRLEN),
("szDeviceID", TTCHAR*TT_STRLEN),
("nWaveDeviceID", INT32),
("bSupports3D", BOOL),
("nMaxInputChannels", INT32),
("nMaxOutputChannels", INT32),
("inputSampleRates", INT32 * TT_SAMPLERATES_MAX),
("outputSampleRates", INT32 * TT_SAMPLERATES_MAX),
("nDefaultSampleRate", INT32),
("uSoundDeviceFeatures", UINT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.SOUNDDEVICE) == ctypes.sizeof(SoundDevice))
TT_SOUNDDEVICE_ID_SHARED_FLAG = 0x00000800
TT_SOUNDDEVICE_ID_MASK = 0x000007FF
TT_SOUNDDEVICE_ID_REMOTEIO = 0
TT_SOUNDDEVICE_ID_VOICEPREPROCESSINGIO = (1 | TT_SOUNDDEVICE_ID_SHARED_FLAG)
TT_SOUNDDEVICE_ID_OPENSLES_DEFAULT = 0
TT_SOUNDDEVICE_ID_OPENSLES_VOICECOM = 1
TT_SOUNDDEVICE_ID_TEAMTALK_VIRTUAL = 1978
class SoundDeviceEffects(Structure):
_fields_ = [
("bEnableAGC", BOOL),
("bEnableDenoise", BOOL),
("bEnableEchoCancellation", BOOL)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.SoundDeviceEffects) == ctypes.sizeof(SoundDeviceEffects))
class SoundLevel(INT32):
SOUND_VU_MAX = 100
SOUND_VU_MIN = 0
SOUND_VOLUME_MAX = 32000
SOUND_VOLUME_DEFAULT = 1000
SOUND_VOLUME_MIN = 0
SOUND_GAIN_MAX = 32000
SOUND_GAIN_DEFAULT = 1000
SOUND_GAIN_MIN = 0
class AudioBlock(Structure):
_fields_ = [
("nStreamID", INT32),
("nSampleRate", INT32),
("nChannels", INT32),
("lpRawAudio", c_void_p),
("nSamples", INT32),
("uSampleIndex", UINT32),
("uStreamTypes", UINT32),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.AUDIOBLOCK) == ctypes.sizeof(AudioBlock))
TT_LOCAL_USERID = 0
TT_LOCAL_TX_USERID = 0x1002
TT_MUXED_USERID = 0x1001
class MediaFileStatus(INT32):
MFS_CLOSED = 0
MFS_ERROR = 1
MFS_STARTED = 2
MFS_FINISHED = 3
MFS_ABORTED = 4
MFS_PAUSED = 5
MFS_PLAYING = 6
class AudioFileFormat(INT32):
AFF_NONE = 0
AFF_CHANNELCODEC_FORMAT = 1
AFF_WAVE_FORMAT = 2
AFF_MP3_16KBIT_FORMAT = 3
AFF_MP3_32KBIT_FORMAT = 4
AFF_MP3_64KBIT_FORMAT = 5
AFF_MP3_128KBIT_FORMAT = 6
AFF_MP3_256KBIT_FORMAT = 7
AFF_MP3_320KBIT_FORMAT = 8
class AudioFormat(Structure):
_fields_ = [
("nAudioFmt", INT32),
("nSampleRate", INT32),
("nChannels", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.AUDIOFORMAT) == ctypes.sizeof(AudioFormat))
class FourCC(INT32):
FOURCC_NONE = 0
FOURCC_I420 = 100
FOURCC_YUY2 = 101
FOURCC_RGB32 = 102
class VideoFormat(Structure):
_fields_ = [
("nWidth", INT32),
("nHeight", INT32),
("nFPS_Numerator", INT32),
("nFPS_Denominator", INT32),
("picFourCC", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.VIDEOFORMAT) == ctypes.sizeof(VideoFormat))
class VideoFrame(Structure):
_fields_ = [
("nWidth", INT32),
("nHeight", INT32),
("nStreamID", INT32),
("bKeyFrame", BOOL),
("frameBuffer", c_void_p),
("nFrameBufferSize", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.VIDEOFRAME) == ctypes.sizeof(VideoFrame))
class VideoCaptureDevice(Structure):
_fields_ = [
("szDeviceID", TTCHAR*TT_STRLEN),
("szDeviceName", TTCHAR*TT_STRLEN),
("szCaptureAPI", TTCHAR*TT_STRLEN),
("videoFormats", VideoFormat*TT_VIDEOFORMATS_MAX),
("nVideoFormatsCount", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.VIDEOCAPTUREDEVICE) == ctypes.sizeof(VideoCaptureDevice))
class BitmapFormat(INT32):
BMP_NONE = 0
BMP_RGB8_PALETTE = 1
BMP_RGB16_555 = 2
BMP_RGB24 = 3
BMP_RGB32 = 4
class DesktopProtocol(INT32):
DESKTOPPROTOCOL_ZLIB_1 = 1
class DesktopWindow(Structure):
_fields_ = [
("nWidth", INT32),
("nHeight", INT32),
("bmpFormat", INT32),
("nBytesPerLine", INT32),
("nSessionID", INT32),
("nProtocol", INT32),
("frameBuffer", c_void_p),
("nFrameBufferSize", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.DESKTOPWINDOW) == ctypes.sizeof(DesktopWindow))
class DesktopKeyState(UINT32):
DESKTOPKEYSTATE_NONE = 0x00000000
DESKTOPKEYSTATE_DOWN = 0x00000001
DESKTOPKEYSTATE_UP = 0x00000002
class DesktopInput(Structure):
_fields_ = [
("uMousePosX", c_uint16),
("uMousePosY", c_uint16),
("uKeyCode", UINT32),
("uKeyState", UINT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.DESKTOPINPUT) == ctypes.sizeof(DesktopInput))
class SpeexCodec(Structure):
_fields_ = [
("nBandmode", INT32),
("nQuality", INT32),
("nTxIntervalMSec", INT32),
("bStereoPlayback", BOOL)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.SPEEXCODEC) == ctypes.sizeof(SpeexCodec))
class SpeexVBRCodec(Structure):
_fields_ = [
("nBandmode", INT32),
("nQuality", INT32),
("nBitRate", INT32),
("nMaxBitRate", INT32),
("bDTX", BOOL),
("nTxIntervalMSec", INT32),
("bStereoPlayback", BOOL)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.SPEEXVBRCODEC) == ctypes.sizeof(SpeexVBRCodec))
SPEEX_NB_MIN_BITRATE = 2150
SPEEX_NB_MAX_BITRATE = 24600
SPEEX_WB_MIN_BITRATE = 3950
SPEEX_WB_MAX_BITRATE = 42200
SPEEX_UWB_MIN_BITRATE = 4150
SPEEX_UWB_MAX_BITRATE = 44000
class OpusCodec(Structure):
_fields_ = [
("nSampleRate", INT32),
("nChannels", INT32),
("nApplication", INT32),
("nComplexity", INT32),
("bFEC", BOOL),
("bDTX", BOOL),
("nBitRate", INT32),
("bVBR", BOOL),
("bVBRConstraint", BOOL),
("nTxIntervalMSec", INT32),
("nFrameSizeMSec", INT32),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.OPUSCODEC) == ctypes.sizeof(OpusCodec))
OPUS_APPLICATION_VOIP = 2048
OPUS_APPLICATION_AUDIO = 2049
OPUS_MIN_BITRATE = 6000
OPUS_MAX_BITRATE = 510000
OPUS_MIN_FRAMESIZE = 2
OPUS_MAX_FRAMESIZE = 60
OPUS_REALMAX_FRAMESIZE = 120
class SpeexDSP(Structure):
_fields_ = [
("bEnableAGC", BOOL),
("nGainLevel", INT32),
("nMaxIncDBSec", INT32),
("nMaxDecDBSec", INT32),
("nMaxGainDB", INT32),
("bEnableDenoise", BOOL),
("nMaxNoiseSuppressDB", INT32),
("bEnableEchoCancellation", BOOL),
("nEchoSuppress", INT32),
("nEchoSuppressActive", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.SPEEXDSP) == ctypes.sizeof(SpeexDSP))
class TTAudioPreprocessor(Structure):
_fields_ = [
("nGainLevel", INT32),
("bMuteLeftSpeaker", BOOL),
("bMuteRightSpeaker", BOOL)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.TTAUDIOPREPROCESSOR) == ctypes.sizeof(TTAudioPreprocessor))
class WebRTCAudioPreprocessor(Structure):
_fields_ = [
("preamplifier_bEnable", BOOL),
("preamplifier_fFixedGainFactor", FLOAT),
("echocanceller_bEnable", BOOL),
("noisesuppression_bEnable", BOOL),
("noisesuppression_nLevel", INT32),
("gaincontroller2_bEnable", BOOL),
("gaincontroller2_fixeddigital_fGainDB", FLOAT),
("gaincontroller2_adaptivedigital_bEnable", BOOL),
("gaincontroller2_adaptivedigital_fHeadRoomDB", FLOAT),
("gaincontroller2_adaptivedigital_fMaxGainDB", FLOAT),
("gaincontroller2_adaptivedigital_fInitialGainDB", FLOAT),
("gaincontroller2_adaptivedigital_fMaxGainChangeDBPerSecond", FLOAT),
("gaincontroller2_adaptivedigital_fMaxOutputNoiseLevelDBFS", FLOAT)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.WEBRTCAUDIOPREPROCESSOR) == ctypes.sizeof(WebRTCAudioPreprocessor))
class AudioPreprocessorType(INT32):
NO_AUDIOPREPROCESSOR = 0
SPEEXDSP_AUDIOPREPROCESSOR = 1
TEAMTALK_AUDIOPREPROCESSOR = 2
WEBRTC_AUDIOPREPROCESSOR_OBSOLETE_R4332 = 3
WEBRTC_AUDIOPREPROCESSOR = 4
class AudioPreprocessorUnion(Union):
_fields_ = [
("speexdsp", SpeexDSP),
("ttpreprocessor", TTAudioPreprocessor),
("webrtc", WebRTCAudioPreprocessor)
]
class AudioPreprocessor(Structure):
_anonymous_ = ["u"]
_fields_ = [
("nPreprocessor", INT32),
("u", AudioPreprocessorUnion)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.AUDIOPREPROCESSOR) == ctypes.sizeof(AudioPreprocessor))
class WebMVP8CodecUnion(Union):
_fields_ = [
("nRcTargetBitrate", INT32),
("rc_target_bitrate", UINT32)
]
class WebMVP8Codec(Structure):
_anonymous_ = ["u"]
_fields_ = [
("u", WebMVP8CodecUnion),
("nEncodeDeadline", UINT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.WEBMVP8CODEC) == ctypes.sizeof(WebMVP8Codec))
WEBM_VPX_DL_REALTIME = 1
WEBM_VPX_DL_GOOD_QUALITY = 1000000
WEBM_VPX_DL_BEST_QUALITY = 0
class Codec(INT32):
NO_CODEC = 0
SPEEX_CODEC = 1
SPEEX_VBR_CODEC = 2
OPUS_CODEC = 3
WEBM_VP8_CODEC = 128
class AudioCodecUnion(Union):
_fields_ = [
("speex", SpeexCodec),
("speex_vbr", SpeexVBRCodec),
("opus", OpusCodec)
]
class AudioCodec(Structure):
_anonymous_ = ["u"]
_fields_ = [
("nCodec", INT32),
("u", AudioCodecUnion)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.AUDIOCODEC) == ctypes.sizeof(AudioCodec))
class AudioConfig(Structure):
_fields_ = [
("bEnableAGC", BOOL),
("nGainLevel", INT32),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.AUDIOCONFIG) == ctypes.sizeof(AudioConfig))
class VideoCodecUnion(Union):
_fields_ = [
("webm_vp8", WebMVP8Codec)
]
class VideoCodec(Structure):
_anonymous_ = ["u"]
_fields_ = [
("nCodec", INT32),
("u", VideoCodecUnion)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.VIDEOCODEC) == ctypes.sizeof(VideoCodec))
class MediaFileInfo(Structure):
_fields_ = [
("nStatus", INT32),
("szFileName", TTCHAR*TT_STRLEN),
("audioFmt", AudioFormat),
("videoFmt", VideoFormat),
("uDurationMSec", UINT32),
("uElapsedMSec", UINT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.MEDIAFILEINFO) == ctypes.sizeof(MediaFileInfo))
class MediaFilePlayback(Structure):
_fields_ = [
("uOffsetMSec", UINT32),
("bPaused", BOOL),
("audioPreprocessor", AudioPreprocessor)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.MEDIAFILEPLAYBACK) == ctypes.sizeof(MediaFilePlayback))
TT_MEDIAPLAYBACK_OFFSET_IGNORE = 0xFFFFFFFF
class AudioInputProgress(Structure):
_fields_ = [
("nStreamID", INT32),
("uQueueMSec", UINT32),
("uElapsedMSec", UINT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.AUDIOINPUTPROGRESS) == ctypes.sizeof(AudioInputProgress))
class UserRight(UINT32):
USERRIGHT_NONE = 0x00000000
USERRIGHT_MULTI_LOGIN = 0x00000001
USERRIGHT_VIEW_ALL_USERS = 0x00000002
USERRIGHT_CREATE_TEMPORARY_CHANNEL = 0x00000004
USERRIGHT_MODIFY_CHANNELS = 0x00000008
USERRIGHT_TEXTMESSAGE_BROADCAST = 0x00000010
USERRIGHT_KICK_USERS = 0x00000020
USERRIGHT_BAN_USERS = 0x00000040
USERRIGHT_MOVE_USERS = 0x00000080
USERRIGHT_OPERATOR_ENABLE = 0x00000100
USERRIGHT_UPLOAD_FILES = 0x00000200
USERRIGHT_DOWNLOAD_FILES = 0x00000400
USERRIGHT_UPDATE_SERVERPROPERTIES = 0x00000800
USERRIGHT_TRANSMIT_VOICE = 0x00001000
USERRIGHT_TRANSMIT_VIDEOCAPTURE = 0x00002000
USERRIGHT_TRANSMIT_DESKTOP = 0x00004000
USERRIGHT_TRANSMIT_DESKTOPINPUT = 0x00008000
USERRIGHT_TRANSMIT_MEDIAFILE_AUDIO = 0x00010000
USERRIGHT_TRANSMIT_MEDIAFILE_VIDEO = 0x00020000
USERRIGHT_TRANSMIT_MEDIAFILE = USERRIGHT_TRANSMIT_MEDIAFILE_VIDEO | USERRIGHT_TRANSMIT_MEDIAFILE_AUDIO
USERRIGHT_LOCKED_NICKNAME = 0x00040000
USERRIGHT_LOCKED_STATUS = 0x00080000
USERRIGHT_RECORD_VOICE = 0x00100000
USERRIGHT_VIEW_HIDDEN_CHANNELS = 0x00200000
USERRIGHT_TEXTMESSAGE_USER = 0x00400000
USERRIGHT_TEXTMESSAGE_CHANNEL = 0x00800000
class ServerLogEvent(UINT32):
SERVERLOGEVENT_NONE = 0x00000000
SERVERLOGEVENT_USER_CONNECTED = 0x00000001
SERVERLOGEVENT_USER_DISCONNECTED = 0x00000002
SERVERLOGEVENT_USER_LOGGEDIN = 0x00000004
SERVERLOGEVENT_USER_LOGGEDOUT = 0x00000008
SERVERLOGEVENT_USER_LOGINFAILED = 0x00000010
SERVERLOGEVENT_USER_TIMEDOUT = 0x00000020
SERVERLOGEVENT_USER_KICKED = 0x00000040
SERVERLOGEVENT_USER_BANNED = 0x00000080
SERVERLOGEVENT_USER_UNBANNED = 0x00000100
SERVERLOGEVENT_USER_UPDATED = 0x00000200
SERVERLOGEVENT_USER_JOINEDCHANNEL = 0x00000400
SERVERLOGEVENT_USER_LEFTCHANNEL = 0x00000800
SERVERLOGEVENT_USER_MOVED = 0x00001000
SERVERLOGEVENT_USER_TEXTMESSAGE_PRIVATE = 0x00002000
SERVERLOGEVENT_USER_TEXTMESSAGE_CUSTOM = 0x00004000
SERVERLOGEVENT_USER_TEXTMESSAGE_CHANNEL = 0x00008000
SERVERLOGEVENT_USER_TEXTMESSAGE_BROADCAST = 0x00010000
SERVERLOGEVENT_CHANNEL_CREATED = 0x00020000
SERVERLOGEVENT_CHANNEL_UPDATED = 0x00040000
SERVERLOGEVENT_CHANNEL_REMOVED = 0x00080000
SERVERLOGEVENT_FILE_UPLOADED = 0x00100000
SERVERLOGEVENT_FILE_DOWNLOADED = 0x00200000
SERVERLOGEVENT_FILE_DELETED = 0x00400000
SERVERLOGEVENT_SERVER_UPDATED = 0x00800000
SERVERLOGEVENT_SERVER_SAVECONFIG = 0x01000000
class ServerProperties(Structure):
_fields_ = [
("szServerName", TTCHAR*TT_STRLEN),
("szMOTD", TTCHAR*TT_STRLEN),
("szMOTDRaw", TTCHAR*TT_STRLEN),
("nMaxUsers", INT32),
("nMaxLoginAttempts", INT32),
("nMaxLoginsPerIPAddress", INT32),
("nMaxVoiceTxPerSecond", INT32),
("nMaxVideoCaptureTxPerSecond", INT32),
("nMaxMediaFileTxPerSecond", INT32),
("nMaxDesktopTxPerSecond", INT32),
("nMaxTotalTxPerSecond", INT32),
("bAutoSave", BOOL),
("nTcpPort", INT32),
("nUdpPort", INT32),
("nUserTimeout", INT32),
("szServerVersion", TTCHAR*TT_STRLEN),
("szServerProtocolVersion", TTCHAR*TT_STRLEN),
("nLoginDelayMSec", INT32),
("szAccessToken", TTCHAR*TT_STRLEN),
("uServerLogEvents", UINT32),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.SERVERPROPERTIES) == ctypes.sizeof(ServerProperties))
class ServerStatistics(Structure):
_fields_ = [
("nTotalBytesTX", INT64),
("nTotalBytesRX", INT64),
("nVoiceBytesTX", INT64),
("nVoiceBytesRX", INT64),
("nVideoCaptureBytesTX", INT64),
("nVideoCaptureBytesRX", INT64),
("nMediaFileBytesTX", INT64),
("nMediaFileBytesRX", INT64),
("nDesktopBytesTX", INT64),
("nDesktopBytesRX", INT64),
("nUsersServed", INT32),
("nUsersPeak", INT32),
("nFilesTx", INT64),
("nFilesRx", INT64),
("nUptimeMSec", INT64)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.SERVERSTATISTICS) == ctypes.sizeof(ServerStatistics))
class BanType(UINT32):
BANTYPE_NONE = 0x00
BANTYPE_CHANNEL = 0x01
BANTYPE_IPADDR = 0x02
BANTYPE_USERNAME = 0x04
class BannedUser(Structure):
_fields_ = [
("szIPAddress", TTCHAR*TT_STRLEN),
("szChannelPath", TTCHAR*TT_STRLEN),
("szBanTime", TTCHAR*TT_STRLEN),
("szNickname", TTCHAR*TT_STRLEN),
("szUsername", TTCHAR*TT_STRLEN),
("uBanTypes", UINT32),
("szOwner", TTCHAR*TT_STRLEN)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.BANNEDUSER) == ctypes.sizeof(BannedUser))
class UserType(UINT32):
USERTYPE_NONE = 0x0
USERTYPE_DEFAULT = 0x01
USERTYPE_ADMIN = 0x02
class AbusePrevention(Structure):
_fields_ = [
("nCommandsLimit", INT32),
("nCommandsIntervalMSec", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.ABUSEPREVENTION) == ctypes.sizeof(AbusePrevention))
class UserAccount(Structure):
_fields_ = [
("szUsername", TTCHAR*TT_STRLEN),
("szPassword", TTCHAR*TT_STRLEN),
("uUserType", UINT32),
("uUserRights", UINT32),
("nUserData", INT32),
("szNote", TTCHAR*TT_STRLEN),
("szInitChannel", TTCHAR*TT_STRLEN),
("autoOperatorChannels", INT32*TT_CHANNELS_OPERATOR_MAX),
("nAudioCodecBpsLimit", INT32),
("abusePrevent", AbusePrevention),
("szLastModified", TTCHAR*TT_STRLEN),
("szLastLoginTime", TTCHAR*TT_STRLEN),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.USERACCOUNT) == ctypes.sizeof(UserAccount))
class Subscription(UINT32):
SUBSCRIBE_NONE = 0x00000000
SUBSCRIBE_USER_MSG = 0x00000001
SUBSCRIBE_CHANNEL_MSG = 0x00000002
SUBSCRIBE_BROADCAST_MSG = 0x00000004
SUBSCRIBE_CUSTOM_MSG = 0x00000008
SUBSCRIBE_VOICE = 0x00000010
SUBSCRIBE_VIDEOCAPTURE = 0x00000020
SUBSCRIBE_DESKTOP = 0x00000040
SUBSCRIBE_DESKTOPINPUT = 0x00000080
SUBSCRIBE_MEDIAFILE = 0x00000100
SUBSCRIBE_INTERCEPT_USER_MSG = 0x00010000
SUBSCRIBE_INTERCEPT_CHANNEL_MSG = 0x00020000
SUBSCRIBE_INTERCEPT_CUSTOM_MSG = 0x00080000
SUBSCRIBE_INTERCEPT_VOICE = 0x00100000
SUBSCRIBE_INTERCEPT_VIDEOCAPTURE = 0x00200000
SUBSCRIBE_INTERCEPT_DESKTOP = 0x00400000
SUBSCRIBE_INTERCEPT_MEDIAFILE = 0x01000000
class UserState(UINT32):
USERSTATE_NONE = 0x0000000
USERSTATE_VOICE = 0x00000001
USERSTATE_MUTE_VOICE = 0x00000002
USERSTATE_MUTE_MEDIAFILE = 0x00000004
USERSTATE_DESKTOP = 0x00000008
USERSTATE_VIDEOCAPTURE = 0x00000010
USERSTATE_MEDIAFILE_AUDIO = 0x00000020
USERSTATE_MEDIAFILE_VIDEO = 0x00000040
USERSTATE_MEDIAFILE = USERSTATE_MEDIAFILE_AUDIO | USERSTATE_MEDIAFILE_VIDEO
class User(Structure):
_fields_ = [
("nUserID", INT32),
("szUsername", TTCHAR * TT_STRLEN),
("nUserData", INT32),
("uUserType", UINT32),
("szIPAddress", TTCHAR * TT_STRLEN),
("uVersion", UINT32),
("nChannelID", INT32),
("uLocalSubscriptions", UINT32),
("uPeerSubscriptions", UINT32),
("szNickname", TTCHAR * TT_STRLEN),
("nStatusMode", INT32),
("szStatusMsg", TTCHAR * TT_STRLEN),
("uUserState", UINT32),
("szMediaStorageDir", TTCHAR * TT_STRLEN),
("nVolumeVoice", INT32),
("nVolumeMediaFile", INT32),
("nStoppedDelayVoice", INT32),
("nStoppedDelayMediaFile", INT32),
("soundPositionVoice", c_float*3),
("soundPositionMediaFile", c_float*3),
("stereoPlaybackVoice", BOOL*2),
("stereoPlaybackMediaFile", BOOL*2),
("nBufferMSecVoice", INT32),
("nBufferMSecMediaFile", INT32),
("nActiveAdaptiveDelayMSec", INT32),
("szClientName", TTCHAR * TT_STRLEN)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.USER) == ctypes.sizeof(User))
class UserStatistics(Structure):
_fields_ = [
("nVoicePacketsRecv", INT64),
("nVoicePacketsLost", INT64),
("nVideoCapturePacketsRecv", INT64),
("nVideoCaptureFramesRecv", INT64),
("nVideoCaptureFramesLost", INT64),
("nVideoCaptureFramesDropped", INT64),
("nMediaFileAudioPacketsRecv", INT64),
("nMediaFileAudioPacketsLost", INT64),
("nMediaFileVideoPacketsRecv", INT64),
("nMediaFileVideoFramesRecv", INT64),
("nMediaFileVideoFramesLost", INT64),
("nMediaFileVideoFramesDropped", INT64),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.USERSTATISTICS) == ctypes.sizeof(UserStatistics))
class TextMsgType(INT32):
MSGTYPE_NONE = 0
MSGTYPE_USER = 1
MSGTYPE_CHANNEL = 2
MSGTYPE_BROADCAST = 3
MSGTYPE_CUSTOM = 4
class TextMessage(Structure):
_fields_ = [
("nMsgType", INT32),
("nFromUserID", INT32),
("szFromUsername", TTCHAR*TT_STRLEN),
("nToUserID", INT32),
("nChannelID", INT32),
("szMessage", TTCHAR*TT_STRLEN),
("bMore", BOOL),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.TEXTMESSAGE) == ctypes.sizeof(TextMessage))
class ChannelType(UINT32):
CHANNEL_DEFAULT = 0x0000
CHANNEL_PERMANENT = 0x0001
CHANNEL_SOLO_TRANSMIT = 0x0002
CHANNEL_CLASSROOM = 0x0004
CHANNEL_OPERATOR_RECVONLY = 0x0008
CHANNEL_NO_VOICEACTIVATION = 0x0010
CHANNEL_NO_RECORDING = 0x0020
CHANNEL_HIDDEN = 0x0040
class Channel(Structure):
_fields_ = [
("nParentID", INT32),
("nChannelID", INT32),
("szName", TTCHAR*TT_STRLEN),
("szTopic", TTCHAR*TT_STRLEN),
("szPassword", TTCHAR*TT_STRLEN),
("bPassword", BOOL),
("uChannelType", UINT32),
("nUserData", INT32),
("nDiskQuota", INT64),
("szOpPassword", TTCHAR*TT_STRLEN),
("nMaxUsers", INT32),
("audiocodec", AudioCodec),
("audiocfg", AudioConfig),
("transmitUsers", (INT32*2)*TT_TRANSMITUSERS_MAX),
("transmitUsersQueue", INT32*TT_TRANSMITQUEUE_MAX),
("nTransmitUsersQueueDelayMSec", INT32),
("nTimeOutTimerVoiceMSec", INT32),
("nTimeOutTimerMediaFileMSec", INT32),
]
def __init__(self):
assert(DBG_SIZEOF(TTType.CHANNEL) == ctypes.sizeof(Channel))
class FileTransferStatus(INT32):
FILETRANSFER_CLOSED = 0
FILETRANSFER_ERROR = 1
FILETRANSFER_ACTIVE = 2
FILETRANSFER_FINISHED = 3
class FileTransfer(Structure):
_fields_ = [
("nStatus", INT32),
("nTransferID", INT32),
("nChannelID", INT32),
("szLocalFilePath", TTCHAR*TT_STRLEN),
("szRemoteFileName", TTCHAR*TT_STRLEN),
("nFileSize", INT64),
("nTransferred", INT64),
("bInbound", BOOL)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.FILETRANSFER) == ctypes.sizeof(FileTransfer))
class RemoteFile(Structure):
_fields_ = [
("nChannelID", INT32),
("nFileID", INT32),
("szFileName", TTCHAR*TT_STRLEN),
("nFileSize", INT64),
("szUsername", TTCHAR*TT_STRLEN),
("szUploadTime", TTCHAR*TT_STRLEN)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.REMOTEFILE) == ctypes.sizeof(RemoteFile))
class EncryptionContext(Structure):
_fields_ = [
("szCertificateFile", TTCHAR*TT_STRLEN),
("szPrivateKeyFile", TTCHAR*TT_STRLEN),
("szCAFile", TTCHAR*TT_STRLEN),
("szCADir", TTCHAR*TT_STRLEN),
("bVerifyPeer", BOOL),
("bVerifyClientOnce", BOOL),
("nVerifyDepth", INT32)
]
class ClientKeepAlive(Structure):
_fields_ = [
("nConnectionLostMSec", INT32),
("nTcpKeepAliveIntervalMSec", INT32),
("nUdpKeepAliveIntervalMSec", INT32),
("nUdpKeepAliveRTXMSec", INT32),
("nUdpConnectRTXMSec", INT32),
("nUdpConnectTimeoutMSec", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.CLIENTKEEPALIVE) == ctypes.sizeof(ClientKeepAlive))
class ClientStatistics(Structure):
_fields_ = [
("nUdpBytesSent", INT64),
("nUdpBytesRecv", INT64),
("nVoiceBytesSent", INT64),
("nVoiceBytesRecv", INT64),
("nVideoCaptureBytesSent", INT64),
("nVideoCaptureBytesRecv", INT64),
("nMediaFileAudioBytesSent", INT64),
("nMediaFileAudioBytesRecv", INT64),
("nMediaFileVideoBytesSent", INT64),
("nMediaFileVideoBytesRecv", INT64),
("nDesktopBytesSent", INT64),
("nDesktopBytesRecv", INT64),
("nUdpPingTimeMs", INT32),
("nTcpPingTimeMs", INT32),
("nTcpServerSilenceSec", INT32),
("nUdpServerSilenceSec", INT32),
("nSoundInputDeviceDelayMSec", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.CLIENTSTATISTICS) == ctypes.sizeof(ClientStatistics))
class JitterConfig(Structure):
_fields_ = [
("nFixedDelayMSec", INT32),
("bUseAdativeDejitter", BOOL),
("nMaxAdaptiveDelayMSec", INT32),
("nActiveAdaptiveDelayMSec", INT32)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.JITTERCONFIG) == ctypes.sizeof(JitterConfig))
class ClientError(INT32):
CMDERR_SUCCESS = 0
CMDERR_SYNTAX_ERROR = 1000
CMDERR_UNKNOWN_COMMAND = 1001
CMDERR_MISSING_PARAMETER = 1002
CMDERR_INCOMPATIBLE_PROTOCOLS = 1003
CMDERR_UNKNOWN_AUDIOCODEC = 1004
CMDERR_INVALID_USERNAME = 1005
CMDERR_INCORRECT_CHANNEL_PASSWORD = 2001
CMDERR_INVALID_ACCOUNT = 2002
CMDERR_MAX_SERVER_USERS_EXCEEDED = 2003
CMDERR_MAX_CHANNEL_USERS_EXCEEDED = 2004
CMDERR_SERVER_BANNED = 2005
CMDERR_NOT_AUTHORIZED = 2006
CMDERR_MAX_DISKUSAGE_EXCEEDED = 2008
CMDERR_INCORRECT_OP_PASSWORD = 2010
CMDERR_AUDIOCODEC_BITRATE_LIMIT_EXCEEDED = 2011
CMDERR_MAX_LOGINS_PER_IPADDRESS_EXCEEDED = 2012
CMDERR_MAX_CHANNELS_EXCEEDED = 2013
CMDERR_COMMAND_FLOOD = 2014
CMDERR_CHANNEL_BANNED = 2015
CMDERR_MAX_FILETRANSFERS_EXCEEDED = 2016
CMDERR_NOT_LOGGEDIN = 3000
CMDERR_ALREADY_LOGGEDIN = 3001
CMDERR_NOT_IN_CHANNEL = 3002
CMDERR_ALREADY_IN_CHANNEL = 3003
CMDERR_CHANNEL_ALREADY_EXISTS = 3004
CMDERR_CHANNEL_NOT_FOUND = 3005
CMDERR_USER_NOT_FOUND = 3006
CMDERR_BAN_NOT_FOUND = 3007
CMDERR_FILETRANSFER_NOT_FOUND = 3008
CMDERR_OPENFILE_FAILED = 3009
CMDERR_ACCOUNT_NOT_FOUND = 3010
CMDERR_FILE_NOT_FOUND = 3011
CMDERR_FILE_ALREADY_EXISTS = 3012
CMDERR_FILESHARING_DISABLED = 3013
CMDERR_CHANNEL_HAS_USERS = 3015
CMDERR_LOGINSERVICE_UNAVAILABLE = 3016
CMDERR_CHANNEL_CANNOT_BE_HIDDEN = 3017
INTERR_SNDINPUT_FAILURE = 10000
INTERR_SNDOUTPUT_FAILURE = 10001
INTERR_AUDIOCODEC_INIT_FAILED = 10002
INTERR_SPEEXDSP_INIT_FAILED = 10003
INTERR_TTMESSAGE_QUEUE_OVERFLOW = 10004
INTERR_SNDEFFECT_FAILURE = 10005
class ClientErrorMsg(Structure):
_fields_ = [
("nErrorNo", INT32),
("szErrorMsg", TTCHAR*TT_STRLEN)
]
def __init__(self):
assert(DBG_SIZEOF(TTType.CLIENTERRORMSG) == ctypes.sizeof(ClientErrorMsg))
class ClientEvent(UINT32):
CLIENTEVENT_NONE = 0
CLIENTEVENT_CON_SUCCESS = CLIENTEVENT_NONE + 10
CLIENTEVENT_CON_CRYPT_ERROR = CLIENTEVENT_NONE + 15
CLIENTEVENT_CON_FAILED = CLIENTEVENT_NONE + 20
CLIENTEVENT_CON_LOST = CLIENTEVENT_NONE + 30
CLIENTEVENT_CON_MAX_PAYLOAD_UPDATED = CLIENTEVENT_NONE + 40
CLIENTEVENT_CMD_PROCESSING = CLIENTEVENT_NONE + 200
CLIENTEVENT_CMD_ERROR = CLIENTEVENT_NONE + 210
CLIENTEVENT_CMD_SUCCESS = CLIENTEVENT_NONE + 220
CLIENTEVENT_CMD_MYSELF_LOGGEDIN = CLIENTEVENT_NONE + 230
CLIENTEVENT_CMD_MYSELF_LOGGEDOUT = CLIENTEVENT_NONE + 240
CLIENTEVENT_CMD_MYSELF_KICKED = CLIENTEVENT_NONE + 250
CLIENTEVENT_CMD_USER_LOGGEDIN = CLIENTEVENT_NONE + 260
CLIENTEVENT_CMD_USER_LOGGEDOUT = CLIENTEVENT_NONE + 270
CLIENTEVENT_CMD_USER_UPDATE = CLIENTEVENT_NONE + 280
CLIENTEVENT_CMD_USER_JOINED = CLIENTEVENT_NONE + 290
CLIENTEVENT_CMD_USER_LEFT = CLIENTEVENT_NONE + 300
CLIENTEVENT_CMD_USER_TEXTMSG = CLIENTEVENT_NONE + 310
CLIENTEVENT_CMD_CHANNEL_NEW = CLIENTEVENT_NONE + 320
CLIENTEVENT_CMD_CHANNEL_UPDATE = CLIENTEVENT_NONE + 330
CLIENTEVENT_CMD_CHANNEL_REMOVE = CLIENTEVENT_NONE + 340
CLIENTEVENT_CMD_SERVER_UPDATE = CLIENTEVENT_NONE + 350
CLIENTEVENT_CMD_SERVERSTATISTICS = CLIENTEVENT_NONE + 360
CLIENTEVENT_CMD_FILE_NEW = CLIENTEVENT_NONE + 370
CLIENTEVENT_CMD_FILE_REMOVE = CLIENTEVENT_NONE + 380
CLIENTEVENT_CMD_USERACCOUNT = CLIENTEVENT_NONE + 390
CLIENTEVENT_CMD_BANNEDUSER = CLIENTEVENT_NONE + 400
CLIENTEVENT_CMD_USERACCOUNT_NEW = CLIENTEVENT_NONE + 410
CLIENTEVENT_CMD_USERACCOUNT_REMOVE = CLIENTEVENT_NONE + 420
CLIENTEVENT_USER_STATECHANGE = CLIENTEVENT_NONE + 500
CLIENTEVENT_USER_VIDEOCAPTURE = CLIENTEVENT_NONE + 510
CLIENTEVENT_USER_MEDIAFILE_VIDEO = CLIENTEVENT_NONE + 520
CLIENTEVENT_USER_DESKTOPWINDOW = CLIENTEVENT_NONE + 530
CLIENTEVENT_USER_DESKTOPCURSOR = CLIENTEVENT_NONE + 540
CLIENTEVENT_USER_DESKTOPINPUT = CLIENTEVENT_NONE + 550
CLIENTEVENT_USER_RECORD_MEDIAFILE = CLIENTEVENT_NONE + 560
CLIENTEVENT_USER_AUDIOBLOCK = CLIENTEVENT_NONE + 570
CLIENTEVENT_INTERNAL_ERROR = CLIENTEVENT_NONE + 1000
CLIENTEVENT_VOICE_ACTIVATION = CLIENTEVENT_NONE + 1010
CLIENTEVENT_HOTKEY = CLIENTEVENT_NONE + 1020
CLIENTEVENT_HOTKEY_TEST = CLIENTEVENT_NONE + 1030
CLIENTEVENT_FILETRANSFER = CLIENTEVENT_NONE + 1040
CLIENTEVENT_DESKTOPWINDOW_TRANSFER = CLIENTEVENT_NONE + 1050
CLIENTEVENT_STREAM_MEDIAFILE = CLIENTEVENT_NONE + 1060
CLIENTEVENT_LOCAL_MEDIAFILE = CLIENTEVENT_NONE + 1070
CLIENTEVENT_AUDIOINPUT = CLIENTEVENT_NONE + 1080
CLIENTEVENT_USER_FIRSTVOICESTREAMPACKET = CLIENTEVENT_NONE + 1090
CLIENTEVENT_SOUNDDEVICE_ADDED = CLIENTEVENT_NONE + 1100
CLIENTEVENT_SOUNDDEVICE_REMOVED = CLIENTEVENT_NONE + 1110
CLIENTEVENT_SOUNDDEVICE_UNPLUGGED = CLIENTEVENT_NONE + 1120
CLIENTEVENT_SOUNDDEVICE_NEW_DEFAULT_INPUT = CLIENTEVENT_NONE + 1130
CLIENTEVENT_SOUNDDEVICE_NEW_DEFAULT_OUTPUT = CLIENTEVENT_NONE + 1140
CLIENTEVENT_SOUNDDEVICE_NEW_DEFAULT_INPUT_COMDEVICE = CLIENTEVENT_NONE + 1150
CLIENTEVENT_SOUNDDEVICE_NEW_DEFAULT_OUTPUT_COMDEVICE = CLIENTEVENT_NONE + 1160
# Underscore has special meaning in Python, so we remove it
class TTType(INT32):
NONE = 0
AUDIOCODEC = 1
BANNEDUSER = 2
VIDEOFORMAT = 3
OPUSCODEC = 4
CHANNEL = 5
CLIENTSTATISTICS = 6
REMOTEFILE = 7
FILETRANSFER = 8
MEDIAFILESTATUS = 9
SERVERPROPERTIES = 10
SERVERSTATISTICS = 11
SOUNDDEVICE = 12
SPEEXCODEC = 13
TEXTMESSAGE = 14
WEBMVP8CODEC = 15
TTMESSAGE = 16