├── .gitignore ├── LICENSE ├── README.md ├── addons └── sourcemod │ ├── extensions │ └── voicemanager.autoload │ ├── gamedata │ └── voicemanager.txt │ └── scripting │ ├── include │ └── voicemanager.inc │ └── voicemanager.sp ├── build.bat ├── build_ext.bat ├── build_ext.sh ├── build_ext_windows.bat ├── build_plugin.bat ├── build_plugin.sh └── extension ├── AMBuildScript ├── AMBuilder ├── CDetour ├── detourhelpers.h ├── detours.cpp └── detours.h ├── CRC.h ├── Dockerfile ├── Dockerfile.windows ├── PackageScript ├── asm ├── asm.c └── asm.h ├── configure.py ├── defines.h ├── docker-compose.windows.yml ├── docker-compose.yml ├── extension.cpp ├── extension.h ├── include ├── celt │ ├── arch.h │ ├── celt.h │ ├── ecintrin.h │ ├── entcode.h │ ├── entdec.h │ ├── entenc.h │ ├── mathops.h │ └── os_support.h ├── opus-dev.lib ├── opus.dll ├── opus.lib ├── opus │ └── opus.h ├── opus1.3.1.lib ├── opus_custom.h ├── opus_defines.h ├── opus_multistream.h ├── opus_projection.h └── opus_types.h ├── inetmessage.h ├── libc_compat.cpp ├── scripts ├── build.bat ├── build.sh └── setup.py ├── smsdk_config.h ├── smsdk_ext.h ├── voicemanager.cpp ├── voicemanager.h ├── voicemanagerclientstate.cpp └── voicemanagerclientstate.h /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | obj-linux-x86_64 3 | ./extension/include 4 | .vscode 5 | spcomp 6 | spcomp.exe 7 | addons/sourcemod/plugins 8 | addons/sourcemod/extensions/voicemanager.ext* 9 | deploy_* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Voice Manager 2 | 3 |
4 | A sourcemod plugin and extension that allows players to individually modify the voice volume of other players. 5 |
6 |
7 |

View Demo on YouTube 8 |
9 |
10 | 11 | [![Demo](https://i3.ytimg.com/vi/5lFNonAkXDQ/maxresdefault.jpg)](https://youtu.be/5lFNonAkXDQ "Voice Manager Sourcemod Extension and Plugin Demo") 12 |

13 |
14 | 15 | ## How To Use 16 | A player can type the command `/vm` into chat to display a menu that allows them to set volume overrides for players in the server. Overrides can be set for invidual players or globally for all players (individual overrides will take precedence). 17 | 18 | ![277191737-b882ee1c-3e8d-4ca4-94db-0448c03f876a](https://github.com/SouthernCrossGaming/voicemanager/assets/20617130/be666240-5ae6-42d3-9073-d8ebdb23d9ac) 19 | 20 | When a volume adjustment is made, all voice communications from that player will be adjusted accordingly. 21 | 22 | There are currently 5 volume levels that can be selected: 23 | 24 | ![277191747-171bb8bf-4a6c-4e0b-a7eb-fb970ec07137](https://github.com/SouthernCrossGaming/voicemanager/assets/20617130/66ae51c2-fb66-4315-8a07-16052b76a2fa) 25 | 26 | ## Requirements 27 | 28 | ### Supported Games* 29 | - Team Fortress 2 30 | - Open Fortress 31 | 32 | * Voice Manager would likely work with any game that supports the steam voice codec. I would be happy to add support for other games by request so long as testing assistance for said game is provided. 33 | 34 | ### Supported Platforms 35 | - Linux 36 | - Windows 37 | 38 | ### Sourcemod 39 | - Version 1.10+ 40 | 41 | ### Supported Database Drivers 42 | - mysql 43 | - sqlite 44 | 45 | ### Supported Voice Codecs 46 | - steam (`sv_voicecodec steam`) 47 | 48 | ## Installation 49 | Download the [latest release](https://github.com/SouthernCrossGaming/voicemanager/releases/latest/download/voicemanager.zip), unzip and copy to your `addons` directory. 50 | 51 | Add a configuration for the voice manager database to your `addons/sourcemod/configs/databases.cfg` file. Note that voice manager will use the "default" configuration by default, but this can be configured via cvar, see below. 52 | 53 | ## Configuration 54 | `vm_enabled` - Enables or disables voice manager (0/1, default 1) 55 | `vm_database` - Database configuration to use from databases.cfg (default is "default") 56 | `vm_allow_self` - Allow players to override their own volume. This is recommended only for testing (0/1, default 0) 57 | 58 | ## Commands 59 | `/vm` | `/voicemanager` - Opens the Voice Manager menu 60 | `/vmclear` - Clears the player's overrides from the database 61 | 62 | ## Building 63 | 64 | ### Build Extension for Linux 65 | 66 | *Requires Docker (with docker compose) using Linux containers 67 | ``` 68 | > .\build_ext.bat 69 | ``` 70 | ``` 71 | $ ./build_ext.sh 72 | ``` 73 | 74 | ### Build Extension for Windows 75 | 76 | *Requires Windows environment with Docker (with docker compose) using Windows containers 77 | ``` 78 | > .\build_ext_windows.bat 79 | ``` 80 | 81 | ### Build Plugin 82 | *Requires spcomp (1.10 or higher) added to your path or to the base directory 83 | ``` 84 | > .\build_plugin.bat 85 | ``` 86 | ``` 87 | $ ./build_plugin.sh 88 | ``` 89 | 90 | ### Build All (Windows environment only) 91 | ``` 92 | > .\build.bat 93 | ``` 94 | 95 | ## VS Code Setup 96 | To setup C++ includes for VS Code, clone sourcemod, metamod, and the tf2 sdk. Include the following paths: 97 | - `./` 98 | - `./include` 99 | - `` 100 | - `\public` 101 | - `\public\extensions` 102 | - `\sourcepawn\include` 103 | - `\sourcepawn\third_party\amtl` 104 | - `\sourcepawn\third_party\amtl\amtl` 105 | - `\core` 106 | - `\core\sourcehook` 107 | - `\public` 108 | - `\public\tier0` 109 | - `\public\tier1` 110 | 111 | ### Troubleshooting 112 | - Problem: The VoiceManager plugin/extension did not load. 113 | - Potential Solution: Check for any errors on startup and ensure that an empty `voicemanager.autoload` file exists under the `addons/sourcemod/extension` directory. 114 | 115 |
116 | 117 | * Problem: When an adjustment is applied, there are no errors but the player does not have any voice output. 118 | * Potential Solution: Make sure the server is using the `steam` voice codec (`sv_voicecodec steam`) 119 | 120 | # Credits 121 | - [Fraeven](https://fraeven.dev) (Extension Code, Plugin Code, Testing) 122 | - [Rowedahelicon](https://rowdythecrux.dev) (Plugin Code, Debugging Assistance, Testing) 123 | - Many members of the SCG community (Testing) 124 | 125 | # AlliedModders Thread 126 | https://forums.alliedmods.net/showthread.php?t=344276 127 | -------------------------------------------------------------------------------- /addons/sourcemod/extensions/voicemanager.autoload: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SouthernCrossGaming/voicemanager/789fa2ee045f2ed4f61412d60dd91d58c6c086b4/addons/sourcemod/extensions/voicemanager.autoload -------------------------------------------------------------------------------- /addons/sourcemod/gamedata/voicemanager.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "tf" 4 | { 5 | "Signatures" 6 | { 7 | "SV_BroadcastVoiceData" 8 | { 9 | "library" "engine" 10 | "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x50\x83\x78\x30" 11 | "linux" "@_Z21SV_BroadcastVoiceDataP7IClientiPcx" 12 | } 13 | } 14 | } 15 | 16 | "open_fortress" 17 | { 18 | "Signatures" 19 | { 20 | "SV_BroadcastVoiceData" 21 | { 22 | "library" "engine" 23 | "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x50\x83\x78\x30" 24 | "linux" "@_Z21SV_BroadcastVoiceDataP7IClientiPcx" 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/include/voicemanager.inc: -------------------------------------------------------------------------------- 1 | /** 2 | * Loads an adjustment for a player into voicemanager 3 | * 4 | * @param adjuster The player invoking the volume adjustment 5 | * @param adjustedSteamId The steam id 64 (string) of the player being adjusted. 6 | * @param volume The volume setting they're being adjusted to 7 | */ 8 | native bool LoadPlayerAdjustment(int caller, char adjustedSteamId[18], int volume); 9 | 10 | /** 11 | * Adjusts the volume of a player for a player 12 | * 13 | * @param caller The player invoking the volume adjustment 14 | * @param client The player being adjusted locally 15 | * @param volume The volume setting they're being adjusted to 16 | */ 17 | native bool OnPlayerAdjustVolume(int caller, int client, int volume); 18 | 19 | native bool OnPlayerGlobalAdjust(int caller, int volume); 20 | 21 | native bool RefreshActiveOverrides(); 22 | 23 | /** 24 | * Clears all overrides a client has set 25 | * 26 | * @param client The player invoking the clear request 27 | */ 28 | native bool ClearClientOverrides(int client); 29 | 30 | /** 31 | * Checks to see if a client has another client muted 32 | * 33 | * @param client The player invoking the request 34 | * @param otherClient The player that is being checked for an override 35 | * 36 | * @return The value of override this client has set on the other client 37 | */ 38 | native int GetClientOverride(int client, int otherClient); -------------------------------------------------------------------------------- /addons/sourcemod/scripting/voicemanager.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define PLUGIN_VERSION "1.0.2" 9 | #define VOICE_MANAGER_PREFIX "{green}[VOICE MANAGER]{default}" 10 | #define TABLE_NAME "voicemanager" 11 | #define STEAM_ID_BUF_SIZE 18 12 | 13 | #pragma newdecls required 14 | 15 | int g_iSelection[MAXPLAYERS+1] = {0}; 16 | int g_iCookieSelection[MAXPLAYERS+1] = {-1}; 17 | char g_sVolumeLevels[4][2] = { "<<", "<", ">", ">>" }; 18 | 19 | char g_sDriver[64]; 20 | 21 | // Cvars 22 | ConVar g_Cvar_VoiceEnable; 23 | ConVar g_Cvar_Database; 24 | ConVar g_Cvar_AllowSelfOverride; 25 | 26 | // Cookies 27 | Handle g_Cookie_GlobalOverride; 28 | 29 | // Handles 30 | Handle g_hDatabase; 31 | 32 | public Extension __ext_voicemanager = 33 | { 34 | name = "VoiceManager", 35 | file = "voicemanager.ext", 36 | required = 1, 37 | } 38 | 39 | public Plugin myinfo = 40 | { 41 | name = "[TF2/OF] Voice Manager", 42 | author = "Fraeven (Extension/Plugin) + Rowedahelicon (Plugin)", 43 | description = "Plugin for Voice Manager Extension", 44 | version = PLUGIN_VERSION, 45 | url = "https://www.scg.wtf" 46 | }; 47 | 48 | public void OnPluginStart() 49 | { 50 | g_Cvar_VoiceEnable = FindConVar("vm_enable"); 51 | g_Cvar_Database = CreateConVar("vm_database", "default", "Database configuration to use from databases.cfg"); 52 | g_Cvar_AllowSelfOverride = CreateConVar("vm_allow_self", "0", "Allow players to override their own volume (recommended only for testing)"); 53 | 54 | RegConsoleCmd("sm_vm", CommandBaseMenu); 55 | RegConsoleCmd("sm_voicemanager", CommandBaseMenu); 56 | RegConsoleCmd("sm_vmclear", Command_ClearClientOverrides); 57 | 58 | HookConVarChange(g_Cvar_VoiceEnable, OnVoiceEnableChanged); 59 | 60 | g_Cookie_GlobalOverride = RegClientCookie("voicemanager_cookie", "VM Global Toggle", CookieAccess_Public); 61 | 62 | SQL_OpenConnection(); 63 | } 64 | 65 | public void SQL_OpenConnection() 66 | { 67 | char database[64]; 68 | g_Cvar_Database.GetString(database, sizeof(database)); 69 | 70 | if (SQL_CheckConfig(database)) 71 | { 72 | SQL_TConnect(T_InitDatabase, database); 73 | } 74 | else 75 | { 76 | SetFailState("Failed to load database config %s from databases.cfg", database); 77 | } 78 | } 79 | 80 | public void T_InitDatabase(Handle owner, Handle hndl, const char[] error, any data) 81 | { 82 | if (hndl != INVALID_HANDLE) 83 | { 84 | g_hDatabase = hndl; 85 | } 86 | else 87 | { 88 | SetFailState("DATABASE FAILURE: %s", error); 89 | } 90 | 91 | SQL_ReadDriver(g_hDatabase, g_sDriver, sizeof(g_sDriver)); 92 | 93 | if (!StrEqual(g_sDriver, "sqlite") && !StrEqual(g_sDriver, "mysql")) 94 | { 95 | SetFailState("Unsupported database driver %s", g_sDriver); 96 | } 97 | 98 | // Add voicemanager table if it does not exist 99 | char szQuery[511]; 100 | Format(szQuery, sizeof(szQuery), "CREATE TABLE IF NOT EXISTS `%s` (adjuster VARCHAR(64), adjusted VARCHAR(64), level TINYINT, PRIMARY KEY (adjuster, adjusted))", TABLE_NAME); 101 | 102 | SQL_TQuery(g_hDatabase, SQLErrorCheckCallback, szQuery); 103 | 104 | for (int client = 1; client <= MaxClients; client++) 105 | { 106 | if (IsValidClient(client)) 107 | { 108 | OnClientPostAdminCheck(client); 109 | OnClientCookiesCached(client); 110 | } 111 | } 112 | } 113 | 114 | public void OnVoiceEnableChanged(ConVar convar, const char[] oldValue, const char[] newValue) 115 | { 116 | RefreshActiveOverrides(); 117 | } 118 | 119 | public void OnClientPostAdminCheck(int client) 120 | { 121 | if (!g_Cvar_VoiceEnable.BoolValue) 122 | { 123 | return; 124 | } 125 | 126 | char szSteamID[STEAM_ID_BUF_SIZE]; 127 | GetClientAuthId(client, AuthId_SteamID64, szSteamID, sizeof(szSteamID)); 128 | 129 | // Load adjustments from database 130 | char szQueryBuffer[255]; 131 | FormatEx(szQueryBuffer, sizeof(szQueryBuffer), "SELECT adjusted, level FROM `%s` WHERE adjuster = '%s'", TABLE_NAME, szSteamID); 132 | SQL_TQuery(g_hDatabase, T_LoadAdjustments, szQueryBuffer, client); 133 | } 134 | 135 | public void T_LoadAdjustments(Handle owner, Handle hndl, const char[] error, int client) 136 | { 137 | if (hndl == INVALID_HANDLE || strlen(error) > 1) 138 | { 139 | LogError("[VoiceManager] Failed to load adjustments: %s", error); 140 | return; 141 | } 142 | 143 | if (SQL_GetRowCount(hndl)) 144 | { 145 | while (SQL_FetchRow(hndl)) 146 | { 147 | // Fetch adjusted steam ids with levels from SQL 148 | char adjustedSteamId[STEAM_ID_BUF_SIZE]; 149 | SQL_FetchString(hndl, 0, adjustedSteamId, sizeof(adjustedSteamId)); 150 | 151 | int level = SQL_FetchInt(hndl, 1); 152 | 153 | LoadPlayerAdjustment(client, adjustedSteamId, level); 154 | } 155 | } 156 | 157 | RefreshActiveOverrides(); 158 | } 159 | 160 | public void OnClientCookiesCached(int client) 161 | { 162 | char sCookieValue[12]; 163 | GetClientCookie(client, g_Cookie_GlobalOverride, sCookieValue, sizeof(sCookieValue)); 164 | 165 | // This is because cookies default to empty and otherwise we use 0 as our lowest volume setting 166 | if (sCookieValue[0] != '\0') 167 | { 168 | int cookieValue = StringToInt(sCookieValue); 169 | g_iCookieSelection[client] = cookieValue; 170 | OnPlayerGlobalAdjust(client, cookieValue); 171 | } 172 | else 173 | { 174 | g_iCookieSelection[client] = -1; 175 | } 176 | } 177 | 178 | public void OnClientDisconnect(int client) 179 | { 180 | if (g_Cvar_VoiceEnable.BoolValue) 181 | { 182 | RefreshActiveOverrides(); 183 | } 184 | } 185 | 186 | // Menus 187 | public Action CommandBaseMenu(int client, int args) 188 | { 189 | if (!g_Cvar_VoiceEnable.BoolValue) 190 | { 191 | return Plugin_Handled; 192 | } 193 | 194 | char playerBuffer[32]; 195 | char stringBuffer[32]; 196 | int playersAdjusted = 0; 197 | 198 | for (int otherClient = 1; otherClient <= MaxClients; otherClient++) 199 | { 200 | if (IsValidClient(otherClient) && (g_Cvar_AllowSelfOverride.BoolValue || otherClient != client) && !IsFakeClient(otherClient) && GetClientOverride(client, otherClient) >= 0) 201 | { 202 | playersAdjusted++; 203 | } 204 | } 205 | 206 | Format(playerBuffer, sizeof(playerBuffer), "Player Adjustment (%i active)", playersAdjusted); 207 | 208 | if (g_iCookieSelection[client] >= 0) 209 | { 210 | Format(stringBuffer, sizeof(stringBuffer), "Global Adjustment (%s)", g_sVolumeLevels[g_iCookieSelection[client]]); 211 | } 212 | else 213 | { 214 | Format(stringBuffer, sizeof(stringBuffer), "Global Adjustment"); 215 | } 216 | 217 | Menu menu = new Menu(BaseMenuHandler); 218 | menu.SetTitle("Voice Manager"); 219 | menu.AddItem("players", playerBuffer); 220 | menu.AddItem("global", stringBuffer); 221 | menu.AddItem("clear", "Clear Player Adjustments"); 222 | menu.ExitButton = true; 223 | menu.Display(client, 20); 224 | 225 | return Plugin_Handled; 226 | } 227 | 228 | public int BaseMenuHandler(Menu menu, MenuAction action, int client, int param2) 229 | { 230 | if (action == MenuAction_Select) 231 | { 232 | char info[32]; 233 | bool found = menu.GetItem(param2, info, sizeof(info)); 234 | 235 | if (found) 236 | { 237 | if (StrEqual(info, "players")) 238 | { 239 | Menu players = new Menu(VoiceMenuHandler); 240 | players.SetTitle("Player Voice Manager"); 241 | 242 | char id[4]; 243 | char name[32]; 244 | 245 | for (int otherClient = 1; otherClient <= MaxClients; otherClient++) 246 | { 247 | if (IsValidClient(otherClient) && (g_Cvar_AllowSelfOverride.BoolValue || otherClient != client) && !IsFakeClient(otherClient)) 248 | { 249 | int override = GetClientOverride(client, otherClient); 250 | 251 | if (override >= 0) 252 | { 253 | Format(name, sizeof(name), "%N (%s)", otherClient, g_sVolumeLevels[override]); 254 | } 255 | else 256 | { 257 | Format(name, sizeof(name), "%N", otherClient); 258 | } 259 | IntToString(otherClient, id, sizeof(id)); 260 | players.AddItem(id, name); 261 | } 262 | } 263 | 264 | if (players.ItemCount == 0) 265 | { 266 | CPrintToChat(client, "%s There are no players to adjust.", VOICE_MANAGER_PREFIX); 267 | return 0; 268 | } 269 | 270 | players.ExitButton = true; 271 | players.ExitBackButton = true; 272 | players.Display(client, 20); 273 | } 274 | else if (StrEqual(info, "global")) 275 | { 276 | Menu global = new Menu(GlobalVoiceVolumeHandler); 277 | 278 | global.SetTitle("Adjust global volume level"); 279 | global.AddItem("3", g_iCookieSelection[client] == 3 ? "Louder *" : "Louder"); 280 | global.AddItem("2", g_iCookieSelection[client] == 2 ? "Loud *" : "Loud"); 281 | global.AddItem("-1", g_iCookieSelection[client] == -1 ? "Normal *" : "Normal"); 282 | global.AddItem("1", g_iCookieSelection[client] == 1 ? "Quiet *" : "Quiet"); 283 | global.AddItem("0", g_iCookieSelection[client] == 0 ? "Quieter *" : "Quieter"); 284 | 285 | global.ExitButton = true; 286 | global.ExitBackButton = true; 287 | global.Display(client, 20); 288 | } 289 | else if (StrEqual(info, "clear")) 290 | { 291 | Menu clear = new Menu(ClearMenuHandler); 292 | 293 | clear.SetTitle("Remove all player volume adjustments?"); 294 | clear.AddItem("1", "Yes"); 295 | clear.AddItem("0", "No"); 296 | 297 | clear.ExitButton = true; 298 | clear.Display(client, 20); 299 | } 300 | } 301 | } 302 | else if (action == MenuAction_Cancel) 303 | { 304 | if (param2 == MenuCancel_ExitBack) 305 | { 306 | CommandBaseMenu(client, 0); 307 | } 308 | } 309 | else if (action == MenuAction_End) 310 | { 311 | delete menu; 312 | } 313 | 314 | return 0; 315 | } 316 | 317 | public Action Command_ClearClientOverrides(int client, int args) 318 | { 319 | if (!g_Cvar_VoiceEnable.BoolValue) 320 | { 321 | return Plugin_Handled; 322 | } 323 | 324 | char szSteamID[STEAM_ID_BUF_SIZE]; 325 | GetClientAuthId(client, AuthId_SteamID64, szSteamID, sizeof(szSteamID)); 326 | 327 | char szQuery[511]; 328 | FormatEx(szQuery, sizeof(szQuery), "DELETE FROM `%s` WHERE adjuster = '%s'", TABLE_NAME, szSteamID); 329 | SQL_TQuery(g_hDatabase, SQLErrorCheckCallback, szQuery); 330 | 331 | ClearClientOverrides(client); 332 | 333 | CPrintToChat(client, "%s You have cleared all of your voice overrides!", VOICE_MANAGER_PREFIX); 334 | 335 | return Plugin_Handled; 336 | 337 | } 338 | 339 | public void OnClearClientOverrides(int client) 340 | { 341 | char szSteamID[STEAM_ID_BUF_SIZE]; 342 | GetClientAuthId(client, AuthId_SteamID64, szSteamID, sizeof(szSteamID)); 343 | 344 | char szQuery[511]; 345 | FormatEx(szQuery, sizeof(szQuery), "DELETE FROM `%s` WHERE adjuster = '%s'", TABLE_NAME, szSteamID); 346 | SQL_TQuery(g_hDatabase, SQLErrorCheckCallback, szQuery); 347 | 348 | ClearClientOverrides(client); 349 | 350 | CPrintToChat(client, "%s You have cleared all of your voice overrides!", VOICE_MANAGER_PREFIX); 351 | } 352 | 353 | //Handlers 354 | public int VoiceMenuHandler(Menu menu, MenuAction action, int param1, int param2) 355 | { 356 | if (action == MenuAction_Select) 357 | { 358 | char info[32]; 359 | bool found = menu.GetItem(param2, info, sizeof(info)); 360 | if (found) 361 | { 362 | int otherClient = StringToInt(info); 363 | int override = GetClientOverride(param1, otherClient); 364 | 365 | g_iSelection[param1] = otherClient; 366 | 367 | Menu sub_menu = new Menu(VoiceVolumeHandler); 368 | 369 | sub_menu.SetTitle("Adjust %N's volume level", otherClient); 370 | sub_menu.AddItem("3", override == 3 ? "Louder *" : "Louder"); 371 | sub_menu.AddItem("2", override == 2 ? "Loud *" : "Loud"); 372 | sub_menu.AddItem("-1", override == -1 ? "Normal *" : "Normal"); 373 | sub_menu.AddItem("1", override == 1 ? "Quiet *" : "Quiet"); 374 | sub_menu.AddItem("0", override == 0 ? "Quieter *" : "Quieter"); 375 | 376 | sub_menu.ExitButton = true; 377 | sub_menu.ExitBackButton = true; 378 | sub_menu.Display(param1, 20); 379 | } 380 | } 381 | else if (action == MenuAction_Cancel) 382 | { 383 | if (param2 == MenuCancel_ExitBack) 384 | { 385 | CommandBaseMenu(param1, 0); 386 | } 387 | } 388 | else if (action == MenuAction_End) 389 | { 390 | delete menu; 391 | } 392 | 393 | return 0; 394 | } 395 | 396 | public int ClearMenuHandler(Menu menu, MenuAction action, int client, int param2) 397 | { 398 | if (action == MenuAction_Select) 399 | { 400 | char info[32]; 401 | menu.GetItem(param2, info, sizeof(info)); 402 | int yes = StringToInt(info); 403 | if (yes) 404 | { 405 | OnClearClientOverrides(client); 406 | } 407 | else 408 | { 409 | CommandBaseMenu(client, 0); 410 | } 411 | } 412 | else if (action == MenuAction_End) 413 | { 414 | delete menu; 415 | } 416 | 417 | return 0; 418 | } 419 | 420 | public int VoiceVolumeHandler(Menu menu, MenuAction action, int client, int param2) 421 | { 422 | if (action == MenuAction_Select) 423 | { 424 | char info[32]; 425 | char setting[32]; 426 | bool found = menu.GetItem(param2, info, sizeof(info), _, setting, sizeof(setting)); 427 | if (found) 428 | { 429 | int level = StringToInt(info); 430 | if (!OnPlayerAdjustVolume(client, g_iSelection[client], level)) 431 | { 432 | CPrintToChat(client, "%s Something went wrong, please try again soon!", VOICE_MANAGER_PREFIX); 433 | } 434 | else 435 | { 436 | CPrintToChat(client, "%s %N's level is now set to %s.", VOICE_MANAGER_PREFIX, g_iSelection[client], setting); 437 | } 438 | 439 | char adjuster[STEAM_ID_BUF_SIZE], adjusted[STEAM_ID_BUF_SIZE]; 440 | GetClientAuthId(client, AuthId_SteamID64, adjuster, sizeof(adjuster)); 441 | GetClientAuthId(client, AuthId_SteamID64, adjusted, sizeof(adjusted)); 442 | 443 | char szQuery[511]; 444 | if (level == -1) 445 | { 446 | FormatEx(szQuery, sizeof(szQuery), "DELETE FROM `%s` WHERE adjuster = '%s' AND adjusted = '%s'", TABLE_NAME, adjuster, adjusted); 447 | SQL_TQuery(g_hDatabase, SQLErrorCheckCallback, szQuery); 448 | } 449 | else 450 | { 451 | char driver[64]; 452 | SQL_ReadDriver(g_hDatabase, driver, sizeof(driver)); 453 | 454 | if (StrEqual(driver, "sqlite")) 455 | { 456 | FormatEx(szQuery, sizeof(szQuery), "\ 457 | INSERT INTO `%s` (adjuster, adjusted, level)\ 458 | VALUES ('%s', '%s', %d)\ 459 | ON CONFLICT(adjuster, adjusted) DO UPDATE SET level = %d", 460 | TABLE_NAME, adjuster, adjusted, level, level); 461 | } 462 | else 463 | { 464 | FormatEx(szQuery, sizeof(szQuery), "\ 465 | INSERT INTO `%s` (adjuster, adjusted, level)\ 466 | VALUES ('%s', '%s', %d)\ 467 | ON DUPLICATE KEY UPDATE level = %d", 468 | TABLE_NAME, adjuster, adjusted, level, level); 469 | } 470 | 471 | SQL_TQuery(g_hDatabase, SQLErrorCheckCallback, szQuery); 472 | } 473 | } 474 | } 475 | else if (action == MenuAction_End) 476 | { 477 | delete menu; 478 | } 479 | 480 | return 0; 481 | } 482 | 483 | public void SQLErrorCheckCallback(Handle owner, Handle hndl, const char[] error, any data) 484 | { 485 | if (hndl == INVALID_HANDLE || strlen(error) > 1) 486 | { 487 | LogError("[VoiceManager] SQL Error: %s", error); 488 | } 489 | } 490 | 491 | public int GlobalVoiceVolumeHandler(Menu menu, MenuAction action, int client, int param2) 492 | { 493 | if (action == MenuAction_Select) 494 | { 495 | char info[32]; 496 | char setting[32]; 497 | bool found = menu.GetItem(param2, info, sizeof(info), _, setting, sizeof(setting)); 498 | if (found) 499 | { 500 | int volume = StringToInt(info); 501 | if (!OnPlayerGlobalAdjust(client, volume)) 502 | { 503 | CPrintToChat(client, "%s Something went wrong, please try again soon!", VOICE_MANAGER_PREFIX); 504 | } 505 | else 506 | { 507 | CPrintToChat(client, "%s Global voice volume is now set to %s.", VOICE_MANAGER_PREFIX, setting); 508 | SetClientCookie(client, g_Cookie_GlobalOverride, info); 509 | g_iCookieSelection[client] = volume; 510 | } 511 | } 512 | } 513 | else if (action == MenuAction_Cancel) 514 | { 515 | if (param2 == MenuCancel_ExitBack) 516 | { 517 | CommandBaseMenu(client, 0); 518 | } 519 | } 520 | else if (action == MenuAction_End) 521 | { 522 | delete menu; 523 | } 524 | 525 | return 0; 526 | } 527 | 528 | stock bool IsValidClient(int client) 529 | { 530 | if (!client || client > MaxClients || client < 1 || !IsClientInGame(client)) 531 | { 532 | return false; 533 | } 534 | 535 | return true; 536 | } -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchLinuxEngine 2 | CALL .\build_ext.bat 3 | "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchWindowsEngine 4 | CALL .\build_ext_windows.bat 5 | 6 | CALL .\build_plugin.bat -------------------------------------------------------------------------------- /build_ext.bat: -------------------------------------------------------------------------------- 1 | DEL addons\sourcemod\extensions\voicemanager.ext.2.sdk2013.so 2 | DEL addons\sourcemod\extensions\voicemanager.ext.2.tf2.so 3 | 4 | cd extension 5 | rmdir build /s /q 6 | docker compose build 7 | docker compose run extension-build --remove-orphans 8 | 9 | echo f | XCOPY build\voicemanager.ext.2.sdk2013\voicemanager.ext.2.sdk2013.so ..\addons\sourcemod\extensions\voicemanager.ext.2.sdk2013.so /Y 10 | echo f | XCOPY build\voicemanager.ext.2.tf2\voicemanager.ext.2.tf2.so ..\addons\sourcemod\extensions\voicemanager.ext.2.tf2.so /Y 11 | cd .. -------------------------------------------------------------------------------- /build_ext.sh: -------------------------------------------------------------------------------- 1 | rm -rf ./addons/sourcemod/extensions 2 | 3 | cd extension 4 | rm -rf ./build 5 | docker compose build 6 | docker compose run extension-build --remove-orphans 7 | 8 | mkdir -p ../addons/sourcemod/extensions 9 | cp build/voicemanager.ext.2.sdk2013/voicemanager.ext.2.sdk2013.so ../addons/sourcemod/extensions/voicemanager.ext.2.sdk2013.so 10 | cp build/voicemanager.ext.2.tf2/voicemanager.ext.2.tf2.so ../addons/sourcemod/extensions/voicemanager.ext.2.tf2.so -------------------------------------------------------------------------------- /build_ext_windows.bat: -------------------------------------------------------------------------------- 1 | DEL addons\sourcemod\extensions\voicemanager.ext.2.sdk2013.dll 2 | DEL addons\sourcemod\extensions\voicemanager.ext.2.tf2.dll 3 | 4 | cd extension 5 | rmdir .\build /s /q 6 | docker compose -f docker-compose.windows.yml build 7 | docker compose -f docker-compose.windows.yml run extension-build-windows --remove-orphans 8 | 9 | echo f | XCOPY build\voicemanager.ext.2.sdk2013\voicemanager.ext.2.sdk2013.dll ..\addons\sourcemod\extensions\voicemanager.ext.2.sdk2013.dll /Y 10 | echo f | XCOPY build\voicemanager.ext.2.tf2\voicemanager.ext.2.tf2.dll ..\addons\sourcemod\extensions\voicemanager.ext.2.tf2.dll /Y 11 | cd .. -------------------------------------------------------------------------------- /build_plugin.bat: -------------------------------------------------------------------------------- 1 | rmdir .\addons\sourcemod\plugins /s /q 2 | mkdir addons\sourcemod\plugins 3 | 4 | spcomp.exe addons\sourcemod\scripting\voicemanager.sp -iaddons\sourcemod\scripting\include -o addons\sourcemod\plugins\voicemanager.smx -------------------------------------------------------------------------------- /build_plugin.sh: -------------------------------------------------------------------------------- 1 | rm -rf ./addons/sourcemod/plugins 2 | mkdir addons/sourcemod/plugins 3 | 4 | ./spcomp addons/sourcemod/scripting/voicemanager.sp -i/usr/include -iaddons/sourcemod/scripting/include -o addons/sourcemod/plugins/voicemanager.smx -------------------------------------------------------------------------------- /extension/AMBuildScript: -------------------------------------------------------------------------------- 1 | # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: 2 | import os, sys 3 | 4 | # Simple extensions do not need to modify this file. 5 | 6 | class SDK(object): 7 | def __init__(self, sdk, ext, aDef, name, platform, dir): 8 | self.folder = 'hl2sdk-' + dir 9 | self.envvar = sdk 10 | self.ext = ext 11 | self.code = aDef 12 | self.define = name 13 | self.platform = platform 14 | self.name = dir 15 | self.path = None # Actual path 16 | 17 | WinOnly = ['windows'] 18 | WinLinux = ['windows', 'linux'] 19 | WinLinuxMac = ['windows', 'linux', 'mac'] 20 | 21 | PossibleSDKs = { 22 | 'episode1': SDK('HL2SDK', '1.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'), 23 | 'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'), 24 | 'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'), 25 | 'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'), 26 | 'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'), 27 | 'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'), 28 | 'tf2': SDK('HL2SDKTF2', '2.tf2', '11', 'TF2', WinLinuxMac, 'tf2'), 29 | 'l4d': SDK('HL2SDKL4D', '2.l4d', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'), 30 | 'nucleardawn': SDK('HL2SDKND', '2.nd', '13', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'), 31 | 'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'), 32 | 'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'), 33 | 'swarm': SDK('HL2SDK-SWARM', '2.swarm', '16', 'ALIENSWARM', WinOnly, 'swarm'), 34 | 'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'), 35 | 'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'), 36 | 'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', WinLinuxMac, 'csgo'), 37 | 'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'), 38 | 'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinLinux, 'blade'), 39 | 'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'), 40 | 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), 41 | 'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), 42 | 'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'), 43 | } 44 | 45 | def ResolveEnvPath(env, folder): 46 | if env in os.environ: 47 | path = os.environ[env] 48 | if os.path.isdir(path): 49 | return path 50 | return None 51 | 52 | head = os.getcwd() 53 | oldhead = None 54 | while head != None and head != oldhead: 55 | path = os.path.join(head, folder) 56 | if os.path.isdir(path): 57 | return path 58 | oldhead = head 59 | head, tail = os.path.split(head) 60 | 61 | return None 62 | 63 | def Normalize(path): 64 | return os.path.abspath(os.path.normpath(path)) 65 | 66 | class ExtensionConfig(object): 67 | def __init__(self): 68 | self.sdks = {} 69 | self.binaries = [] 70 | self.extensions = [] 71 | self.generated_headers = None 72 | self.mms_root = None 73 | self.sm_root = None 74 | 75 | @property 76 | def tag(self): 77 | if builder.options.debug == '1': 78 | return 'Debug' 79 | return 'Release' 80 | 81 | def detectSDKs(self): 82 | sdk_list = builder.options.sdks.split(',') 83 | use_all = sdk_list[0] == 'all' 84 | use_present = sdk_list[0] == 'present' 85 | 86 | for sdk_name in PossibleSDKs: 87 | sdk = PossibleSDKs[sdk_name] 88 | if builder.target_platform in sdk.platform: 89 | if builder.options.hl2sdk_root: 90 | sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder) 91 | else: 92 | sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder) 93 | if sdk_path is None or not os.path.isdir(sdk_path): 94 | if use_all or sdk_name in sdk_list: 95 | raise Exception('Could not find a valid path for {0}'.format(sdk.envvar)) 96 | continue 97 | if use_all or use_present or sdk_name in sdk_list: 98 | sdk.path = Normalize(sdk_path) 99 | self.sdks[sdk_name] = sdk 100 | 101 | if len(self.sdks) < 1: 102 | raise Exception('At least one SDK must be available.') 103 | 104 | if builder.options.sm_path: 105 | self.sm_root = builder.options.sm_path 106 | else: 107 | self.sm_root = ResolveEnvPath('SOURCEMOD111', 'sourcemod-1.11') 108 | if not self.sm_root: 109 | self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod') 110 | if not self.sm_root: 111 | self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central') 112 | 113 | if not self.sm_root or not os.path.isdir(self.sm_root): 114 | raise Exception('Could not find a source copy of SourceMod') 115 | self.sm_root = Normalize(self.sm_root) 116 | 117 | if builder.options.mms_path: 118 | self.mms_root = builder.options.mms_path 119 | else: 120 | self.mms_root = ResolveEnvPath('MMSOURCE111', 'mmsource-1.11') 121 | if not self.mms_root: 122 | self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source') 123 | if not self.mms_root: 124 | self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central') 125 | 126 | if not self.mms_root or not os.path.isdir(self.mms_root): 127 | raise Exception('Could not find a source copy of Metamod:Source') 128 | self.mms_root = Normalize(self.mms_root) 129 | 130 | def configure(self): 131 | cxx = builder.DetectCompilers() 132 | 133 | if cxx.like('gcc'): 134 | self.configure_gcc(cxx) 135 | elif cxx.vendor == 'msvc': 136 | self.configure_msvc(cxx) 137 | 138 | # Optimization 139 | if builder.options.opt == '1': 140 | cxx.defines += ['NDEBUG'] 141 | 142 | # Debugging 143 | if builder.options.debug == '1': 144 | cxx.defines += ['DEBUG', '_DEBUG'] 145 | 146 | # Platform-specifics 147 | if builder.target_platform == 'linux': 148 | self.configure_linux(cxx) 149 | elif builder.target_platform == 'mac': 150 | self.configure_mac(cxx) 151 | elif builder.target_platform == 'windows': 152 | self.configure_windows(cxx) 153 | 154 | # Finish up. 155 | cxx.includes += [ 156 | os.path.join(self.sm_root, 'public') 157 | ] 158 | 159 | def configure_gcc(self, cxx): 160 | cxx.defines += [ 161 | 'stricmp=strcasecmp', 162 | '_stricmp=strcasecmp', 163 | '_snprintf=snprintf', 164 | '_vsnprintf=vsnprintf', 165 | 'HAVE_STDINT_H', 166 | 'GNUC', 167 | ] 168 | cxx.cflags += [ 169 | '-pipe', 170 | '-fno-strict-aliasing', 171 | '-Wall', 172 | '-Wno-unused', 173 | '-Wno-switch', 174 | '-Wno-array-bounds', 175 | '-msse', 176 | '-m32', 177 | '-fvisibility=hidden' 178 | ] 179 | cxx.cxxflags += [ 180 | '-std=c++14', 181 | '-fno-exceptions', 182 | '-fno-threadsafe-statics', 183 | '-Wno-non-virtual-dtor', 184 | '-Wno-overloaded-virtual', 185 | '-fvisibility-inlines-hidden' 186 | ] 187 | cxx.linkflags += ['-m32'] 188 | 189 | have_gcc = cxx.vendor == 'gcc' 190 | have_clang = cxx.vendor == 'clang' 191 | if cxx.version >= 'clang-3.6': 192 | cxx.cxxflags += ['-Wno-inconsistent-missing-override'] 193 | if have_clang or (cxx.version >= 'gcc-4.6'): 194 | cxx.cflags += ['-Wno-narrowing'] 195 | if have_clang or (cxx.version >= 'gcc-4.7'): 196 | cxx.cxxflags += ['-Wno-delete-non-virtual-dtor'] 197 | if cxx.version >= 'gcc-4.8': 198 | cxx.cflags += ['-Wno-unused-result'] 199 | 200 | if have_clang: 201 | cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch'] 202 | if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4': 203 | cxx.cxxflags += ['-Wno-deprecated-register'] 204 | else: 205 | cxx.cxxflags += ['-Wno-deprecated'] 206 | cxx.cflags += ['-Wno-sometimes-uninitialized'] 207 | 208 | if have_gcc: 209 | cxx.cflags += ['-mfpmath=sse'] 210 | 211 | if builder.options.opt == '1': 212 | cxx.cflags += ['-O3'] 213 | 214 | def configure_msvc(self, cxx): 215 | if builder.options.debug == '1': 216 | cxx.cflags += ['/MTd'] 217 | cxx.linkflags += ['/NODEFAULTLIB:libcmt'] 218 | else: 219 | cxx.cflags += ['/MT'] 220 | cxx.defines += [ 221 | '_CRT_SECURE_NO_DEPRECATE', 222 | '_CRT_SECURE_NO_WARNINGS', 223 | '_CRT_NONSTDC_NO_DEPRECATE', 224 | '_ITERATOR_DEBUG_LEVEL=0', 225 | ] 226 | cxx.cflags += [ 227 | '/W3', 228 | ] 229 | cxx.cxxflags += [ 230 | '/std:c++17', 231 | '/EHsc', 232 | '/GR-', 233 | '/TP', 234 | ] 235 | cxx.linkflags += [ 236 | '/MACHINE:X86', 237 | 'kernel32.lib', 238 | 'user32.lib', 239 | 'gdi32.lib', 240 | 'winspool.lib', 241 | 'comdlg32.lib', 242 | 'advapi32.lib', 243 | 'shell32.lib', 244 | 'ole32.lib', 245 | 'oleaut32.lib', 246 | 'uuid.lib', 247 | 'odbc32.lib', 248 | 'odbccp32.lib', 249 | 'legacy_stdio_definitions.lib', 250 | 'C:\\extension\\include\\opus1.3.1.lib' 251 | ] 252 | 253 | if builder.options.opt == '1': 254 | cxx.cflags += ['/Ox', '/Zo'] 255 | cxx.linkflags += ['/OPT:ICF', '/OPT:REF'] 256 | 257 | if builder.options.debug == '1': 258 | cxx.cflags += ['/Od', '/RTC1'] 259 | 260 | # This needs to be after our optimization flags which could otherwise disable it. 261 | # Don't omit the frame pointer. 262 | cxx.cflags += ['/Oy-'] 263 | 264 | def configure_linux(self, cxx): 265 | cxx.defines += ['_LINUX', 'POSIX'] 266 | cxx.linkflags += ['-Wl,--exclude-libs,ALL', '/usr/local/lib/libopus.a'] 267 | if cxx.vendor == 'gcc': 268 | cxx.linkflags += ['-static-libgcc'] 269 | elif cxx.vendor == 'clang': 270 | cxx.linkflags += ['-lgcc_eh'] 271 | cxx.linkflags += ['-lm'] 272 | 273 | def configure_mac(self, cxx): 274 | cxx.defines += ['OSX', '_OSX', 'POSIX'] 275 | cxx.cflags += ['-mmacosx-version-min=10.5'] 276 | cxx.linkflags += [ 277 | '-mmacosx-version-min=10.5', 278 | '-arch', 'i386', 279 | '-lstdc++', 280 | '-stdlib=libstdc++', 281 | ] 282 | cxx.cxxflags += ['-stdlib=libstdc++'] 283 | 284 | def configure_windows(self, cxx): 285 | cxx.defines += ['WIN32', '_WINDOWS'] 286 | 287 | def ConfigureForExtension(self, context, compiler): 288 | compiler.cxxincludes += [ 289 | os.path.join(context.currentSourcePath), 290 | os.path.join(context.currentSourcePath, 'include'), 291 | os.path.join(context.currentSourcePath, 'sdk'), 292 | os.path.join(self.sm_root, 'public'), 293 | os.path.join(self.sm_root, 'public', 'extensions'), 294 | os.path.join(self.sm_root, 'sourcepawn', 'include'), 295 | os.path.join(self.sm_root, 'public', 'amtl', 'amtl'), 296 | os.path.join(self.sm_root, 'public', 'amtl'), 297 | ] 298 | return compiler 299 | 300 | def ConfigureForHL2(self, binary, sdk): 301 | compiler = binary.compiler 302 | 303 | if sdk.name == 'episode1': 304 | mms_path = os.path.join(self.mms_root, 'core-legacy') 305 | else: 306 | mms_path = os.path.join(self.mms_root, 'core') 307 | 308 | compiler.cxxincludes += [ 309 | os.path.join(mms_path), 310 | os.path.join(mms_path, 'sourcehook'), 311 | ] 312 | 313 | defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs] 314 | compiler.defines += defines 315 | 316 | paths = [ 317 | ['public'], 318 | ['public', 'engine'], 319 | ['public', 'mathlib'], 320 | ['public', 'vstdlib'], 321 | ['public', 'tier0'], 322 | ['public', 'tier1'] 323 | ] 324 | if sdk.name == 'episode1' or sdk.name == 'darkm': 325 | paths.append(['public', 'dlls']) 326 | paths.append(['game_shared']) 327 | else: 328 | paths.append(['public', 'game', 'server']) 329 | paths.append(['public', 'toolframework']) 330 | paths.append(['game', 'shared']) 331 | paths.append(['common']) 332 | 333 | compiler.defines += ['SOURCE_ENGINE=' + sdk.code] 334 | 335 | if sdk.name in ['sdk2013']: 336 | compiler.defines += ['REPLAY_ENABLED'] 337 | 338 | if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'): 339 | # The 2013 SDK already has these in public/tier0/basetypes.h 340 | compiler.defines.remove('stricmp=strcasecmp') 341 | compiler.defines.remove('_stricmp=strcasecmp') 342 | compiler.defines.remove('_snprintf=snprintf') 343 | compiler.defines.remove('_vsnprintf=vsnprintf') 344 | 345 | if compiler.like('msvc'): 346 | compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32'] 347 | else: 348 | compiler.defines += ['COMPILER_GCC'] 349 | 350 | # For everything after Swarm, this needs to be defined for entity networking 351 | # to work properly with sendprop value changes. 352 | if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']: 353 | compiler.defines += ['NETWORK_VARS_ENABLED'] 354 | 355 | if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']: 356 | if builder.target_platform in ['linux', 'mac']: 357 | compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE'] 358 | 359 | if sdk.name == 'csgo' and builder.target_platform == 'linux': 360 | compiler.linkflags += ['-lstdc++'] 361 | 362 | for path in paths: 363 | compiler.cxxincludes += [os.path.join(sdk.path, *path)] 364 | 365 | if builder.target_platform == 'linux': 366 | if sdk.name == 'episode1': 367 | lib_folder = os.path.join(sdk.path, 'linux_sdk') 368 | elif sdk.name in ['sdk2013', 'bms']: 369 | lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32') 370 | else: 371 | lib_folder = os.path.join(sdk.path, 'lib', 'linux') 372 | elif builder.target_platform == 'mac': 373 | if sdk.name in ['sdk2013', 'bms']: 374 | lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32') 375 | else: 376 | lib_folder = os.path.join(sdk.path, 'lib', 'mac') 377 | 378 | if builder.target_platform in ['linux', 'mac']: 379 | if sdk.name in ['sdk2013', 'bms']: 380 | compiler.postlink += [ 381 | compiler.Dep(os.path.join(lib_folder, 'tier1.a')), 382 | compiler.Dep(os.path.join(lib_folder, 'mathlib.a')) 383 | ] 384 | else: 385 | compiler.postlink += [ 386 | compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')), 387 | compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a')) 388 | ] 389 | 390 | if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']: 391 | compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))] 392 | 393 | dynamic_libs = [] 394 | if builder.target_platform == 'linux': 395 | if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']: 396 | dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so'] 397 | elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']: 398 | dynamic_libs = ['libtier0.so', 'libvstdlib.so'] 399 | else: 400 | dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so'] 401 | elif builder.target_platform == 'mac': 402 | compiler.linkflags.append('-liconv') 403 | dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib'] 404 | elif builder.target_platform == 'windows': 405 | libs = ['tier0', 'tier1', 'vstdlib', 'mathlib'] 406 | if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']: 407 | libs.append('interfaces') 408 | for lib in libs: 409 | lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib' 410 | compiler.linkflags.append(compiler.Dep(lib_path)) 411 | 412 | for library in dynamic_libs: 413 | source_path = os.path.join(lib_folder, library) 414 | output_path = os.path.join(binary.localFolder, library) 415 | 416 | def make_linker(source_path, output_path): 417 | def link(context, binary): 418 | cmd_node, (output,) = context.AddSymlink(source_path, output_path) 419 | return output 420 | return link 421 | 422 | linker = make_linker(source_path, output_path) 423 | compiler.linkflags[0:0] = [compiler.Dep(library, linker)] 424 | 425 | return binary 426 | 427 | def HL2Library(self, context, name, sdk): 428 | binary = context.compiler.Library(name) 429 | self.ConfigureForExtension(context, binary.compiler) 430 | return self.ConfigureForHL2(binary, sdk) 431 | 432 | def HL2Project(self, context, name): 433 | project = context.compiler.LibraryProject(name) 434 | self.ConfigureForExtension(context, project.compiler) 435 | return project 436 | 437 | def HL2Config(self, project, name, sdk): 438 | binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name)) 439 | return self.ConfigureForHL2(binary, sdk) 440 | 441 | Extension = ExtensionConfig() 442 | Extension.detectSDKs() 443 | Extension.configure() 444 | 445 | # Add additional buildscripts here 446 | BuildScripts = [ 447 | 'AMBuilder', 448 | ] 449 | 450 | if builder.backend == 'amb2': 451 | BuildScripts += [ 452 | 'PackageScript', 453 | ] 454 | 455 | builder.RunBuildScripts(BuildScripts, { 'Extension': Extension}) 456 | -------------------------------------------------------------------------------- /extension/AMBuilder: -------------------------------------------------------------------------------- 1 | # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: 2 | import os, sys 3 | 4 | projectName = 'voicemanager' 5 | 6 | # smsdk_ext.cpp will be automatically added later 7 | sourceFiles = [ 8 | 'extension.cpp', 9 | 'voicemanager.cpp', 10 | 'voicemanagerclientstate.cpp', 11 | 'CDetour/detours.cpp', 12 | 'asm/asm.c' 13 | ] 14 | 15 | ############### 16 | # Make sure to edit PackageScript, which copies your files to their appropriate locations 17 | # Simple extensions do not need to modify past this point. 18 | 19 | project = Extension.HL2Project(builder, projectName + '.ext') 20 | 21 | if os.path.isfile(os.path.join(builder.currentSourcePath, 'sdk', 'smsdk_ext.cpp')): 22 | # Use the copy included in the project 23 | project.sources += [os.path.join('sdk', 'smsdk_ext.cpp')] 24 | else: 25 | # Use the copy included with SM 1.6 and newer 26 | project.sources += [os.path.join(Extension.sm_root, 'public', 'smsdk_ext.cpp')] 27 | 28 | project.sources += sourceFiles 29 | 30 | for sdk_name in Extension.sdks: 31 | if sdk_name in ['sdk2013'] and builder.target_platform == 'linux': 32 | project.sources += ['libc_compat.cpp'] 33 | 34 | sdk = Extension.sdks[sdk_name] 35 | 36 | binary = Extension.HL2Config(project, projectName + '.ext.' + sdk.ext, sdk) 37 | 38 | Extension.extensions = builder.Add(project) 39 | -------------------------------------------------------------------------------- /extension/CDetour/detourhelpers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 : 3 | * ============================================================================= 4 | * SourceMod 5 | * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. 6 | * ============================================================================= 7 | * 8 | * This program is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU General Public License, version 3.0, as published by the 10 | * Free Software Foundation. 11 | * 12 | * This program is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License along with 18 | * this program. If not, see . 19 | * 20 | * As a special exception, AlliedModders LLC gives you permission to link the 21 | * code of this program (as well as its derivative works) to "Half-Life 2," the 22 | * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software 23 | * by the Valve Corporation. You must obey the GNU General Public License in 24 | * all respects for all other code used. Additionally, AlliedModders LLC grants 25 | * this exception to all derivative works. AlliedModders LLC defines further 26 | * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), 27 | * or . 28 | * 29 | * Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $ 30 | */ 31 | 32 | #ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_ 33 | #define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_ 34 | 35 | #if defined PLATFORM_POSIX 36 | #include 37 | #define PAGE_SIZE 4096 38 | #define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1)) 39 | #define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC 40 | #endif 41 | 42 | struct patch_t 43 | { 44 | patch_t() 45 | { 46 | patch[0] = 0; 47 | bytes = 0; 48 | } 49 | unsigned char patch[20]; 50 | size_t bytes; 51 | }; 52 | 53 | inline void ProtectMemory(void *addr, int length, int prot) 54 | { 55 | #if defined PLATFORM_POSIX 56 | void *addr2 = (void *)ALIGN(addr); 57 | mprotect(addr2, sysconf(_SC_PAGESIZE), prot); 58 | #elif defined PLATFORM_WINDOWS 59 | DWORD old_prot; 60 | VirtualProtect(addr, length, prot, &old_prot); 61 | #endif 62 | } 63 | 64 | inline void SetMemPatchable(void *address, size_t size) 65 | { 66 | ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE); 67 | } 68 | 69 | inline void DoGatePatch(unsigned char *target, void *callback) 70 | { 71 | SetMemPatchable(target, 20); 72 | 73 | target[0] = 0xFF; /* JMP */ 74 | target[1] = 0x25; /* MEM32 */ 75 | *(void **)(&target[2]) = callback; 76 | } 77 | 78 | inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore) 79 | { 80 | ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE); 81 | 82 | unsigned char *addr = (unsigned char *)address + offset; 83 | if (restore) 84 | { 85 | for (size_t i=0; ibytes; i++) 86 | { 87 | restore->patch[i] = addr[i]; 88 | } 89 | restore->bytes = patch->bytes; 90 | } 91 | 92 | for (size_t i=0; ibytes; i++) 93 | { 94 | addr[i] = patch->patch[i]; 95 | } 96 | } 97 | 98 | #endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_ 99 | -------------------------------------------------------------------------------- /extension/CDetour/detours.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 : 3 | * ============================================================================= 4 | * SourceMod 5 | * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. 6 | * ============================================================================= 7 | * 8 | * This program is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU General Public License, version 3.0, as published by the 10 | * Free Software Foundation. 11 | * 12 | * This program is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License along with 18 | * this program. If not, see . 19 | * 20 | * As a special exception, AlliedModders LLC gives you permission to link the 21 | * code of this program (as well as its derivative works) to "Half-Life 2," the 22 | * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software 23 | * by the Valve Corporation. You must obey the GNU General Public License in 24 | * all respects for all other code used. Additionally, AlliedModders LLC grants 25 | * this exception to all derivative works. AlliedModders LLC defines further 26 | * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), 27 | * or . 28 | * 29 | * Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $ 30 | */ 31 | 32 | #include "detours.h" 33 | #include 34 | 35 | ISourcePawnEngine *CDetourManager::spengine = NULL; 36 | IGameConfig *CDetourManager::gameconf = NULL; 37 | 38 | void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf) 39 | { 40 | CDetourManager::spengine = spengine; 41 | CDetourManager::gameconf = gameconf; 42 | } 43 | 44 | CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame) 45 | { 46 | CDetour *detour = new CDetour(callbackfunction, trampoline, signame); 47 | if (detour) 48 | { 49 | if (!detour->Init(spengine, gameconf)) 50 | { 51 | delete detour; 52 | return NULL; 53 | } 54 | 55 | return detour; 56 | } 57 | 58 | return NULL; 59 | } 60 | 61 | CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame) 62 | { 63 | enabled = false; 64 | detoured = false; 65 | detour_address = NULL; 66 | detour_trampoline = NULL; 67 | this->signame = signame; 68 | this->detour_callback = callbackfunction; 69 | spengine = NULL; 70 | gameconf = NULL; 71 | this->trampoline = trampoline; 72 | } 73 | 74 | bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf) 75 | { 76 | this->spengine = spengine; 77 | this->gameconf = gameconf; 78 | 79 | if (!CreateDetour()) 80 | { 81 | enabled = false; 82 | return enabled; 83 | } 84 | 85 | enabled = true; 86 | 87 | return enabled; 88 | } 89 | 90 | void CDetour::Destroy() 91 | { 92 | DeleteDetour(); 93 | delete this; 94 | } 95 | 96 | bool CDetour::IsEnabled() 97 | { 98 | return enabled; 99 | } 100 | 101 | bool CDetour::CreateDetour() 102 | { 103 | if (!gameconf->GetMemSig(signame, &detour_address)) 104 | { 105 | g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame); 106 | return false; 107 | } 108 | 109 | if (!detour_address) 110 | { 111 | g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame); 112 | return false; 113 | } 114 | 115 | detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1); 116 | 117 | /* First, save restore bits */ 118 | for (size_t i=0; iAllocatePageMemory(CodeSize); 147 | spengine->SetReadWrite(wr.outbase); 148 | wr.outptr = wr.outbase; 149 | detour_trampoline = wr.outbase; 150 | goto jit_rewind; 151 | } 152 | 153 | spengine->SetReadExecute(wr.outbase); 154 | 155 | *trampoline = detour_trampoline; 156 | 157 | return true; 158 | } 159 | 160 | void CDetour::DeleteDetour() 161 | { 162 | if (detoured) 163 | { 164 | DisableDetour(); 165 | } 166 | 167 | if (detour_trampoline) 168 | { 169 | /* Free the allocated trampoline memory */ 170 | spengine->FreePageMemory(detour_trampoline); 171 | detour_trampoline = NULL; 172 | } 173 | } 174 | 175 | void CDetour::EnableDetour() 176 | { 177 | if (!detoured) 178 | { 179 | DoGatePatch((unsigned char *)detour_address, &detour_callback); 180 | detoured = true; 181 | } 182 | } 183 | 184 | void CDetour::DisableDetour() 185 | { 186 | if (detoured) 187 | { 188 | /* Remove the patch */ 189 | ApplyPatch(detour_address, 0, &detour_restore, NULL); 190 | detoured = false; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /extension/CDetour/detours.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 : 3 | * ============================================================================= 4 | * SourceMod 5 | * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. 6 | * ============================================================================= 7 | * 8 | * This program is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU General Public License, version 3.0, as published by the 10 | * Free Software Foundation. 11 | * 12 | * This program is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License along with 18 | * this program. If not, see . 19 | * 20 | * As a special exception, AlliedModders LLC gives you permission to link the 21 | * code of this program (as well as its derivative works) to "Half-Life 2," the 22 | * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software 23 | * by the Valve Corporation. You must obey the GNU General Public License in 24 | * all respects for all other code used. Additionally, AlliedModders LLC grants 25 | * this exception to all derivative works. AlliedModders LLC defines further 26 | * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), 27 | * or . 28 | * 29 | * Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $ 30 | */ 31 | 32 | #ifndef _INCLUDE_SOURCEMOD_DETOURS_H_ 33 | #define _INCLUDE_SOURCEMOD_DETOURS_H_ 34 | 35 | #include "../extension.h" 36 | #include 37 | #include 38 | #include "detourhelpers.h" 39 | 40 | /** 41 | * CDetours class for SourceMod Extensions by pRED* 42 | * detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume). 43 | * asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly 44 | * Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/) 45 | * Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp) 46 | */ 47 | 48 | #define DETOUR_MEMBER_CALL(name) (this->*name##_Actual) 49 | #define DETOUR_STATIC_CALL(name) (name##_Actual) 50 | 51 | #define DETOUR_DECL_STATIC0(name, ret) \ 52 | ret (*name##_Actual)(void) = NULL; \ 53 | ret name(void) 54 | 55 | #define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \ 56 | ret (*name##_Actual)(p1type) = NULL; \ 57 | ret name(p1type p1name) 58 | 59 | #define DETOUR_DECL_STATIC2(name, ret, p1type, p1name, p2type, p2name) \ 60 | ret (*name##_Actual)(p1type, p2type) = NULL; \ 61 | ret name(p1type p1name, p2type p2name) 62 | 63 | 64 | #define DETOUR_DECL_STATIC3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \ 65 | ret (*name##_Actual)(p1type, p2type, p3type) = NULL; \ 66 | ret name(p1type p1name, p2type p2name, p3type p3name) 67 | 68 | #define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \ 69 | ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \ 70 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name) 71 | 72 | #define DETOUR_DECL_STATIC5(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name) \ 73 | ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type) = NULL; \ 74 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name) 75 | 76 | #define DETOUR_DECL_STATIC6(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name) \ 77 | ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type) = NULL; \ 78 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name) 79 | 80 | #define DETOUR_DECL_STATIC7(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name) \ 81 | ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type) = NULL; \ 82 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name) 83 | 84 | #define DETOUR_DECL_STATIC0_fastcall(name, ret) \ 85 | ret (__fastcall *name##_Actual)(void) = NULL; \ 86 | ret __fastcall name(void) 87 | 88 | #define DETOUR_DECL_STATIC1_fastcall(name, ret, p1type, p1name) \ 89 | ret (__fastcall *name##_Actual)(p1type) = NULL; \ 90 | ret __fastcall name(p1type p1name) 91 | 92 | #define DETOUR_DECL_STATIC2_fastcall(name, ret, p1type, p1name, p2type, p2name) \ 93 | ret (__fastcall *name##_Actual)(p1type, p2type) = NULL; \ 94 | ret __fastcall name(p1type p1name, p2type p2name) 95 | 96 | #define DETOUR_DECL_STATIC3_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \ 97 | ret (__fastcall *name##_Actual)(p1type, p2type, p3type) = NULL; \ 98 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name) 99 | 100 | #define DETOUR_DECL_STATIC4_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \ 101 | ret (__fastcall *name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \ 102 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name, p4type p4name) 103 | 104 | #define DETOUR_DECL_STATIC5_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name) \ 105 | ret (__fastcall *name##_Actual)(p1type, p2type, p3type, p4type, p5type) = NULL; \ 106 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name) 107 | 108 | #define DETOUR_DECL_STATIC6_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name) \ 109 | ret (__fastcall *name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type) = NULL; \ 110 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name) 111 | 112 | #define DETOUR_DECL_STATIC7_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name) \ 113 | ret (__fastcall *name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type) = NULL; \ 114 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name) 115 | 116 | #define DETOUR_DECL_MEMBER0(name, ret) \ 117 | class name##Class \ 118 | { \ 119 | public: \ 120 | ret name(); \ 121 | static ret (name##Class::* name##_Actual)(void); \ 122 | }; \ 123 | ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \ 124 | ret name##Class::name() 125 | 126 | #define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \ 127 | class name##Class \ 128 | { \ 129 | public: \ 130 | ret name(p1type p1name); \ 131 | static ret (name##Class::* name##_Actual)(p1type); \ 132 | }; \ 133 | ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \ 134 | ret name##Class::name(p1type p1name) 135 | 136 | #define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \ 137 | class name##Class \ 138 | { \ 139 | public: \ 140 | ret name(p1type p1name, p2type p2name); \ 141 | static ret (name##Class::* name##_Actual)(p1type, p2type); \ 142 | }; \ 143 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \ 144 | ret name##Class::name(p1type p1name, p2type p2name) 145 | 146 | #define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \ 147 | class name##Class \ 148 | { \ 149 | public: \ 150 | ret name(p1type p1name, p2type p2name, p3type p3name); \ 151 | static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \ 152 | }; \ 153 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \ 154 | ret name##Class::name(p1type p1name, p2type p2name, p3type p3name) 155 | 156 | #define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \ 157 | class name##Class \ 158 | { \ 159 | public: \ 160 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \ 161 | static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \ 162 | }; \ 163 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \ 164 | ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name) 165 | 166 | #define DETOUR_DECL_MEMBER5(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name) \ 167 | class name##Class \ 168 | { \ 169 | public: \ 170 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name); \ 171 | static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type); \ 172 | }; \ 173 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type) = NULL; \ 174 | ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name) 175 | 176 | #define DETOUR_DECL_MEMBER7(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name) \ 177 | class name##Class \ 178 | { \ 179 | public: \ 180 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name); \ 181 | static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type); \ 182 | }; \ 183 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type) = NULL; \ 184 | ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name) 185 | 186 | #define DETOUR_DECL_MEMBER8(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name) \ 187 | class name##Class \ 188 | { \ 189 | public: \ 190 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name); \ 191 | static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type); \ 192 | }; \ 193 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type) = NULL; \ 194 | ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name) 195 | 196 | #define DETOUR_DECL_MEMBER9(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name) \ 197 | class name##Class \ 198 | { \ 199 | public: \ 200 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name); \ 201 | static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type); \ 202 | }; \ 203 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type) = NULL; \ 204 | ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name) 205 | 206 | #define DETOUR_DECL_MEMBER10(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name) \ 207 | class name##Class \ 208 | { \ 209 | public: \ 210 | ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name); \ 211 | static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type); \ 212 | }; \ 213 | ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type) = NULL; \ 214 | ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name) 215 | 216 | #define DETOUR_DECL_MEMBER0_fastcall(name, ret) \ 217 | class name##Class \ 218 | { \ 219 | public: \ 220 | ret __fastcall name(); \ 221 | static ret (__fastcall name##Class::* name##_Actual)(void); \ 222 | }; \ 223 | ret (__fastcall name##Class::* name##Class::name##_Actual)(void) = NULL; \ 224 | ret __fastcall name##Class::name() 225 | 226 | #define DETOUR_DECL_MEMBER1_fastcall(name, ret, p1type, p1name) \ 227 | class name##Class \ 228 | { \ 229 | public: \ 230 | ret __fastcall name(p1type p1name); \ 231 | static ret (__fastcall name##Class::* name##_Actual)(p1type); \ 232 | }; \ 233 | ret (__fastcall name##Class::* name##Class::name##_Actual)(p1type) = NULL; \ 234 | ret __fastcall name##Class::name(p1type p1name) 235 | 236 | #define DETOUR_DECL_MEMBER2_fastcall(name, ret, p1type, p1name, p2type, p2name) \ 237 | class name##Class \ 238 | { \ 239 | public: \ 240 | ret __fastcall name(p1type p1name, p2type p2name); \ 241 | static ret (__fastcall name##Class::* name##_Actual)(p1type, p2type); \ 242 | }; \ 243 | ret (__fastcall name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \ 244 | ret __fastcall name##Class::name(p1type p1name, p2type p2name) 245 | 246 | #define DETOUR_DECL_MEMBER3_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \ 247 | class name##Class \ 248 | { \ 249 | public: \ 250 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name); \ 251 | static ret (__fastcall name##Class::* name##_Actual)(p1type, p2type, p3type); \ 252 | }; \ 253 | ret (__fastcall name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \ 254 | ret __fastcall name##Class::name(p1type p1name, p2type p2name, p3type p3name) 255 | 256 | #define DETOUR_DECL_MEMBER4_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \ 257 | class name##Class \ 258 | { \ 259 | public: \ 260 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \ 261 | static ret (__fastcall name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \ 262 | }; \ 263 | ret (__fastcall name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \ 264 | ret __fastcall name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name) 265 | 266 | #define DETOUR_DECL_MEMBER5_fastcall(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name) \ 267 | class name##Class \ 268 | { \ 269 | public: \ 270 | ret __fastcall name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name); \ 271 | static ret (__fastcall name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type); \ 272 | }; \ 273 | ret (__fastcall name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type) = NULL; \ 274 | ret __fastcall name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name) 275 | 276 | #define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name) 277 | #define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual) 278 | 279 | #define GET_STATIC_CALLBACK(name) (void *)&name 280 | #define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual 281 | 282 | #define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata); 283 | #define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata); 284 | 285 | 286 | class GenericClass {}; 287 | typedef void (GenericClass::*VoidFunc)(); 288 | 289 | inline void *GetCodeAddr(VoidFunc mfp) 290 | { 291 | return *(void **)&mfp; 292 | } 293 | 294 | /** 295 | * Converts a member function pointer to a void pointer. 296 | * This relies on the assumption that the code address lies at mfp+0 297 | * This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers 298 | * Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp 299 | */ 300 | #define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast(mfp)) 301 | 302 | class CDetourManager; 303 | 304 | class CDetour 305 | { 306 | public: 307 | 308 | bool IsEnabled(); 309 | 310 | /** 311 | * These would be somewhat self-explanatory I hope 312 | */ 313 | void EnableDetour(); 314 | void DisableDetour(); 315 | 316 | void Destroy(); 317 | 318 | friend class CDetourManager; 319 | 320 | protected: 321 | CDetour(void *callbackfunction, void **trampoline, const char *signame); 322 | 323 | bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf); 324 | private: 325 | 326 | /* These create/delete the allocated memory */ 327 | bool CreateDetour(); 328 | void DeleteDetour(); 329 | 330 | bool enabled; 331 | bool detoured; 332 | 333 | patch_t detour_restore; 334 | /* Address of the detoured function */ 335 | void *detour_address; 336 | /* Address of the allocated trampoline function */ 337 | void *detour_trampoline; 338 | /* Address of the callback handler */ 339 | void *detour_callback; 340 | /* The function pointer used to call our trampoline */ 341 | void **trampoline; 342 | 343 | const char *signame; 344 | ISourcePawnEngine *spengine; 345 | IGameConfig *gameconf; 346 | }; 347 | 348 | class CDetourManager 349 | { 350 | public: 351 | 352 | static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf); 353 | 354 | /** 355 | * Creates a new detour 356 | * 357 | * @param callbackfunction Void pointer to your detour callback function. 358 | * @param trampoline Address of the trampoline pointer 359 | * @param signame Section name containing a signature to fetch from the gamedata file. 360 | * @return A new CDetour pointer to control your detour. 361 | * 362 | * Example: 363 | * 364 | * CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int) 365 | * 366 | * Define a new class with the required function and a member function pointer to the same type: 367 | * 368 | * class CBaseServerDetour 369 | * { 370 | * public: 371 | * bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int); 372 | * static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int); 373 | * } 374 | * 375 | * void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient); 376 | * void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual); 377 | * 378 | * Creation: 379 | * CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient"); 380 | * 381 | * Usage: 382 | * 383 | * CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int) 384 | * { 385 | * //pre hook code 386 | * bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params); 387 | * //post hook code 388 | * return result; 389 | * } 390 | * 391 | * Note we changed the netadr_s reference into a void* to avoid needing to define the type 392 | */ 393 | static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame); 394 | 395 | friend class CBlocker; 396 | friend class CDetour; 397 | 398 | private: 399 | static ISourcePawnEngine *spengine; 400 | static IGameConfig *gameconf; 401 | }; 402 | 403 | #define DECL_DETOUR(name) \ 404 | CDetour *name##_Detour = nullptr; 405 | 406 | #define CREATE_DETOUR(name, signname, var) \ 407 | name##_Detour = DETOUR_CREATE_MEMBER(name, signname); \ 408 | if (name##_Detour != NULL) \ 409 | { \ 410 | name##_Detour->EnableDetour(); \ 411 | var = true; \ 412 | } else { \ 413 | g_pSM->LogError(myself, "Failed to create " signname " detour, check error log.\n"); \ 414 | var = false; \ 415 | } 416 | 417 | #define CREATE_DETOUR_STATIC(name, signname, var) \ 418 | name##_Detour = DETOUR_CREATE_STATIC(name, signname); \ 419 | if (name##_Detour != NULL) \ 420 | { \ 421 | name##_Detour->EnableDetour(); \ 422 | var = true; \ 423 | } else { \ 424 | g_pSM->LogError(myself, "Failed to create " signname " detour, check error log.\n"); \ 425 | var = false; \ 426 | } 427 | 428 | #define DESTROY_DETOUR(name) \ 429 | if (name##_Detour != nullptr) \ 430 | { \ 431 | name##_Detour->Destroy(); \ 432 | name##_Detour = nullptr; \ 433 | } 434 | 435 | #endif // _INCLUDE_SOURCEMOD_DETOURS_H_ 436 | -------------------------------------------------------------------------------- /extension/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | RUN apt update 4 | RUN dpkg --add-architecture i386 5 | RUN apt update && apt install -y git python3 python3-pip 6 | 7 | RUN mkdir /sdks 8 | RUN git clone https://github.com/alliedmodders/sourcemod --recurse-submodules -b 1.11-dev 9 | RUN git clone https://github.com/alliedmodders/metamod-source --recurse-submodules -b 1.11-dev 10 | RUN git clone https://github.com/alliedmodders/hl2sdk --recurse-submodules -b tf2 /sdks/hl2sdk-tf2 11 | RUN git clone https://github.com/alliedmodders/hl2sdk --recurse-submodules -b sdk2013 /sdks/hl2sdk-sdk2013 12 | RUN git clone https://github.com/alliedmodders/ambuild --recurse-submodules 13 | 14 | RUN apt install -y \ 15 | g++-multilib \ 16 | libtool \ 17 | nasm \ 18 | libiberty-dev:i386 \ 19 | libelf-dev:i386 \ 20 | libboost-dev:i386 \ 21 | libbsd-dev:i386 \ 22 | libunwind-dev:i386 \ 23 | lib32stdc++-10-dev \ 24 | lib32z1-dev \ 25 | libc6-dev:i386 \ 26 | linux-libc-dev:i386 \ 27 | libopus-dev:i386 28 | 29 | RUN git clone https://github.com/xiph/opus.git -b v1.3.1 --depth 1 30 | RUN cd opus && ./autogen.sh && ./configure CFLAGS="-m32 -g -O2" LDFLAGS=-m32 && make && make install && cd .. 31 | 32 | RUN pip install ./ambuild -------------------------------------------------------------------------------- /extension/Dockerfile.windows: -------------------------------------------------------------------------------- 1 | # escape=` 2 | 3 | FROM mcr.microsoft.com/windows/server:ltsc2022 4 | 5 | # Reset the shell. 6 | SHELL ["cmd", "/S", "/C"] 7 | 8 | # Download channel for fixed install. 9 | ADD https://aka.ms/vs/17/release/channel C:\TEMP\VisualStudio.chman 10 | 11 | # Download and install Build Tools for Visual Studio 2022 for native desktop workload. 12 | ADD https://aka.ms/vs/17/release/vs_buildtools.exe C:\TEMP\vs_buildtools.exe 13 | RUN C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache ` 14 | --channelUri C:\TEMP\VisualStudio.chman ` 15 | --installChannelUri C:\TEMP\VisualStudio.chman ` 16 | --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended` 17 | --installPath C:\BuildTools 18 | 19 | RUN PowerShell Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) 20 | RUN choco install -y ` 21 | git ` 22 | python 23 | 24 | RUN mkdir C:\sdks 25 | RUN git clone https://github.com/alliedmodders/sourcemod --recurse-submodules -b 1.11-dev 26 | RUN git clone https://github.com/alliedmodders/metamod-source --recurse-submodules -b 1.11-dev 27 | RUN git clone https://github.com/alliedmodders/hl2sdk --recurse-submodules -b tf2 C:\sdks\hl2sdk-tf2 28 | RUN git clone https://github.com/alliedmodders/hl2sdk --recurse-submodules -b sdk2013 C:\sdks\hl2sdk-sdk2013 29 | RUN git clone https://github.com/alliedmodders/ambuild --recurse-submodules 30 | 31 | COPY scripts\setup.py C:\ambuild\setup.py 32 | RUN pip install C:\ambuild 33 | 34 | ENTRYPOINT C:\BuildTools\Common7\Tools\VsDevCmd.bat && C:\extension\scripts\build.bat -------------------------------------------------------------------------------- /extension/PackageScript: -------------------------------------------------------------------------------- 1 | # vim: set ts=8 sts=2 sw=2 tw=99 et ft=python: 2 | import os 3 | 4 | # This is where the files will be output to 5 | # package is the default 6 | builder.SetBuildFolder('package') 7 | 8 | # Add any folders you need to this list 9 | folder_list = [ 10 | 'addons/sourcemod/extensions', 11 | #'addons/sourcemod/scripting/include', 12 | #'addons/sourcemod/gamedata', 13 | #'addons/sourcemod/configs', 14 | ] 15 | 16 | # Create the distribution folder hierarchy. 17 | folder_map = {} 18 | for folder in folder_list: 19 | norm_folder = os.path.normpath(folder) 20 | folder_map[folder] = builder.AddFolder(norm_folder) 21 | 22 | # Do all straight-up file copies from the source tree. 23 | def CopyFiles(src, dest, files): 24 | if not dest: 25 | dest = src 26 | dest_entry = folder_map[dest] 27 | for source_file in files: 28 | source_path = os.path.join(builder.sourcePath, src, source_file) 29 | builder.AddCopy(source_path, dest_entry) 30 | 31 | # Include files 32 | #CopyFiles('include', 'addons/sourcemod/scripting/include', 33 | # [ 'sample.inc', ] 34 | #) 35 | 36 | # GameData files 37 | #CopyFiles('gamedata', 'addons/sourcemod/gamedata', 38 | # [ 'myfile.txt', 39 | # 'file2.txt' 40 | # ] 41 | #) 42 | 43 | # Config Files 44 | #CopyFiles('configs', 'addons/sourcemod/configs', 45 | # [ 'configfile.cfg', 46 | # 'otherconfig.cfg, 47 | # ] 48 | #) 49 | 50 | # Copy binaries. 51 | for cxx_task in Extension.extensions: 52 | builder.AddCopy(cxx_task.binary, folder_map['addons/sourcemod/extensions']) 53 | -------------------------------------------------------------------------------- /extension/asm/asm.c: -------------------------------------------------------------------------------- 1 | #include "asm.h" 2 | 3 | #ifndef WIN32 4 | #define _GNU_SOURCE 5 | #include 6 | #include 7 | 8 | #define REG_EAX 0 9 | #define REG_ECX 1 10 | #define REG_EDX 2 11 | #define REG_EBX 3 12 | 13 | #define IA32_MOV_REG_IMM 0xB8 // encoding is +r 14 | #endif 15 | 16 | extern void Msg( const char *, ... ); 17 | 18 | /** 19 | * Checks if a call to a fpic thunk has just been written into dest. 20 | * If found replaces it with a direct mov that sets the required register to the value of pc. 21 | * 22 | * @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written. 23 | * @param pc The program counter value that needs to be set (usually the next address from the source). 24 | * @noreturn 25 | */ 26 | void check_thunks(unsigned char *dest, unsigned char *pc) 27 | { 28 | #if defined WIN32 29 | return; 30 | #else 31 | /* Step write address back 4 to the start of the function address */ 32 | unsigned char *writeaddr = dest - 4; 33 | unsigned char *calloffset = *(unsigned char **)writeaddr; 34 | unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset); 35 | 36 | /* Lookup name of function being called */ 37 | if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3)) 38 | { 39 | //a thunk maybe? 40 | char movByte = IA32_MOV_REG_IMM; 41 | 42 | /* Calculate the correct mov opcode */ 43 | switch (*(calladdr+1)) 44 | { 45 | case 0x04: 46 | { 47 | movByte += REG_EAX; 48 | break; 49 | } 50 | case 0x1C: 51 | { 52 | movByte += REG_EBX; 53 | break; 54 | } 55 | case 0x0C: 56 | { 57 | movByte += REG_ECX; 58 | break; 59 | } 60 | case 0x14: 61 | { 62 | movByte += REG_EDX; 63 | break; 64 | } 65 | default: 66 | { 67 | Msg("Unknown thunk: %c\n", *(calladdr+1)); 68 | break; 69 | } 70 | } 71 | 72 | /* Move our write address back one to where the call opcode was */ 73 | writeaddr--; 74 | 75 | 76 | /* Write our mov */ 77 | *writeaddr = movByte; 78 | writeaddr++; 79 | 80 | /* Write the value - The provided program counter value */ 81 | *(void **)writeaddr = (void *)pc; 82 | writeaddr += 4; 83 | } 84 | 85 | return; 86 | #endif 87 | } 88 | 89 | //if dest is NULL, returns minimum number of bytes needed to be copied 90 | //if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs 91 | //http://www.devmaster.net/forums/showthread.php?t=2311 92 | int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) { 93 | int bytecount = 0; 94 | 95 | while(bytecount < required_len && *func != 0xCC) 96 | { 97 | // prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h 98 | int operandSize = 4; 99 | int FPU = 0; 100 | int twoByte = 0; 101 | unsigned char opcode = 0x90; 102 | unsigned char modRM = 0xFF; 103 | while(*func == 0xF0 || 104 | *func == 0xF2 || 105 | *func == 0xF3 || 106 | (*func & 0xFC) == 0x64 || 107 | (*func & 0xF8) == 0xD8 || 108 | (*func & 0x7E) == 0x62) 109 | { 110 | if(*func == 0x66) 111 | { 112 | operandSize = 2; 113 | } 114 | else if((*func & 0xF8) == 0xD8) 115 | { 116 | FPU = *func; 117 | if (dest) 118 | *dest++ = *func++; 119 | else 120 | func++; 121 | bytecount++; 122 | break; 123 | } 124 | 125 | if (dest) 126 | *dest++ = *func++; 127 | else 128 | func++; 129 | bytecount++; 130 | } 131 | 132 | // two-byte opcode byte 133 | if(*func == 0x0F) 134 | { 135 | twoByte = 1; 136 | if (dest) 137 | *dest++ = *func++; 138 | else 139 | func++; 140 | bytecount++; 141 | } 142 | 143 | // opcode byte 144 | opcode = *func++; 145 | if (dest) *dest++ = opcode; 146 | bytecount++; 147 | 148 | // mod R/M byte 149 | modRM = 0xFF; 150 | if(FPU) 151 | { 152 | if((opcode & 0xC0) != 0xC0) 153 | { 154 | modRM = opcode; 155 | } 156 | } 157 | else if(!twoByte) 158 | { 159 | if((opcode & 0xC4) == 0x00 || 160 | ((opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09)) || 161 | (opcode & 0xF0) == 0x80 || 162 | ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02) || 163 | (opcode & 0xFC) == 0xD0 || 164 | (opcode & 0xF6) == 0xF6) 165 | { 166 | modRM = *func++; 167 | if (dest) *dest++ = modRM; 168 | bytecount++; 169 | } 170 | } 171 | else 172 | { 173 | if(((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) || 174 | (opcode & 0xF0) == 0x30 || 175 | opcode == 0x77 || 176 | (opcode & 0xF0) == 0x80 || 177 | ((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) || 178 | (opcode & 0xF8) == 0xC8) 179 | { 180 | // No mod R/M byte 181 | } 182 | else 183 | { 184 | modRM = *func++; 185 | if (dest) *dest++ = modRM; 186 | bytecount++; 187 | } 188 | } 189 | 190 | // SIB 191 | if((modRM & 0x07) == 0x04 && 192 | (modRM & 0xC0) != 0xC0) 193 | { 194 | if (dest) 195 | *dest++ = *func++; //SIB 196 | else 197 | func++; 198 | bytecount++; 199 | } 200 | 201 | // mod R/M displacement 202 | 203 | // Dword displacement, no base 204 | if((modRM & 0xC5) == 0x05) { 205 | if (dest) { 206 | *(unsigned int*)dest = *(unsigned int*)func; 207 | dest += 4; 208 | } 209 | func += 4; 210 | bytecount += 4; 211 | } 212 | 213 | // Byte displacement 214 | if((modRM & 0xC0) == 0x40) { 215 | if (dest) 216 | *dest++ = *func++; 217 | else 218 | func++; 219 | bytecount++; 220 | } 221 | 222 | // Dword displacement 223 | if((modRM & 0xC0) == 0x80) { 224 | if (dest) { 225 | *(unsigned int*)dest = *(unsigned int*)func; 226 | dest += 4; 227 | } 228 | func += 4; 229 | bytecount += 4; 230 | } 231 | 232 | // immediate 233 | if(FPU) 234 | { 235 | // Can't have immediate operand 236 | } 237 | else if(!twoByte) 238 | { 239 | if((opcode & 0xC7) == 0x04 || 240 | (opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL 241 | (opcode & 0xF0) == 0x70 || // Jcc 242 | opcode == 0x80 || 243 | opcode == 0x83 || 244 | (opcode & 0xFD) == 0xA0 || // MOV 245 | opcode == 0xA8 || // TEST 246 | (opcode & 0xF8) == 0xB0 || // MOV 247 | (opcode & 0xFE) == 0xC0 || // RCL 248 | opcode == 0xC6 || // MOV 249 | opcode == 0xCD || // INT 250 | (opcode & 0xFE) == 0xD4 || // AAD/AAM 251 | (opcode & 0xF8) == 0xE0 || // LOOP/JCXZ 252 | opcode == 0xEB || 253 | (opcode == 0xF6 && (modRM & 0x30) == 0x00)) // TEST 254 | { 255 | if (dest) 256 | *dest++ = *func++; 257 | else 258 | func++; 259 | bytecount++; 260 | } 261 | else if((opcode & 0xF7) == 0xC2) // RET 262 | { 263 | if (dest) { 264 | *(unsigned short*)dest = *(unsigned short*)func; 265 | dest += 2; 266 | } 267 | func += 2; 268 | bytecount += 2; 269 | } 270 | else if((opcode & 0xFC) == 0x80 || 271 | (opcode & 0xC7) == 0x05 || 272 | (opcode & 0xF8) == 0xB8 || 273 | (opcode & 0xFE) == 0xE8 || // CALL/Jcc 274 | (opcode & 0xFE) == 0x68 || 275 | (opcode & 0xFC) == 0xA0 || 276 | (opcode & 0xEE) == 0xA8 || 277 | opcode == 0xC7 || 278 | (opcode == 0xF7 && (modRM & 0x30) == 0x00)) 279 | { 280 | if (dest) { 281 | //Fix CALL/JMP offset 282 | if ((opcode & 0xFE) == 0xE8) { 283 | if (operandSize == 4) 284 | { 285 | *(long*)dest = ((func + *(long*)func) - dest); 286 | 287 | //pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc 288 | check_thunks(dest+4, func+4); 289 | } 290 | else 291 | *(short*)dest = ((func + *(short*)func) - dest); 292 | 293 | } else { 294 | if (operandSize == 4) 295 | *(unsigned long*)dest = *(unsigned long*)func; 296 | else 297 | *(unsigned short*)dest = *(unsigned short*)func; 298 | } 299 | dest += operandSize; 300 | } 301 | func += operandSize; 302 | bytecount += operandSize; 303 | 304 | } 305 | } 306 | else 307 | { 308 | if(opcode == 0xBA || // BT 309 | opcode == 0x0F || // 3DNow! 310 | (opcode & 0xFC) == 0x70 || // PSLLW 311 | (opcode & 0xF7) == 0xA4 || // SHLD 312 | opcode == 0xC2 || 313 | opcode == 0xC4 || 314 | opcode == 0xC5 || 315 | opcode == 0xC6) 316 | { 317 | if (dest) 318 | *dest++ = *func++; 319 | else 320 | func++; 321 | } 322 | else if((opcode & 0xF0) == 0x80) // Jcc -i 323 | { 324 | if (dest) { 325 | if (operandSize == 4) 326 | *(unsigned long*)dest = *(unsigned long*)func; 327 | else 328 | *(unsigned short*)dest = *(unsigned short*)func; 329 | 330 | dest += operandSize; 331 | } 332 | func += operandSize; 333 | bytecount += operandSize; 334 | } 335 | } 336 | } 337 | 338 | return bytecount; 339 | } 340 | 341 | //insert a specific JMP instruction at the given location 342 | void inject_jmp(void* src, void* dest) { 343 | *(unsigned char*)src = OP_JMP; 344 | *(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE)); 345 | } 346 | 347 | //fill a given block with NOPs 348 | void fill_nop(void* src, unsigned int len) { 349 | unsigned char* src2 = (unsigned char*)src; 350 | while (len) { 351 | *src2++ = OP_NOP; 352 | --len; 353 | } 354 | } 355 | 356 | void* eval_jump(void* src) { 357 | unsigned char* addr = (unsigned char*)src; 358 | 359 | if (!addr) return 0; 360 | 361 | //import table jump 362 | if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) { 363 | addr += 2; 364 | addr = *(unsigned char**)addr; 365 | //TODO: if addr points into the IAT 366 | return *(void**)addr; 367 | } 368 | 369 | //8bit offset 370 | else if (addr[0] == OP_JMP_BYTE) { 371 | addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1]; 372 | //mangled 32bit jump? 373 | if (addr[0] == OP_JMP) { 374 | addr = addr + *(int*)&addr[1]; 375 | } 376 | return addr; 377 | } 378 | /* 379 | //32bit offset 380 | else if (addr[0] == OP_JMP) { 381 | addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1]; 382 | } 383 | */ 384 | 385 | return addr; 386 | } 387 | /* 388 | from ms detours package 389 | static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress) 390 | { 391 | MEMORY_BASIC_INFORMATION mbi; 392 | VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi)); 393 | __try { 394 | PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; 395 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 396 | return false; 397 | } 398 | 399 | PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + 400 | pDosHeader->e_lfanew); 401 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { 402 | return false; 403 | } 404 | 405 | if (pbAddress >= ((PBYTE)pDosHeader + 406 | pNtHeader->OptionalHeader 407 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && 408 | pbAddress < ((PBYTE)pDosHeader + 409 | pNtHeader->OptionalHeader 410 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + 411 | pNtHeader->OptionalHeader 412 | .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) { 413 | return true; 414 | } 415 | return false; 416 | } 417 | __except(EXCEPTION_EXECUTE_HANDLER) { 418 | return false; 419 | } 420 | } 421 | */ 422 | -------------------------------------------------------------------------------- /extension/asm/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASM_H__ 2 | #define __ASM_H__ 3 | 4 | #define OP_JMP 0xE9 5 | #define OP_JMP_SIZE 5 6 | 7 | #define OP_NOP 0x90 8 | #define OP_NOP_SIZE 1 9 | 10 | #define OP_PREFIX 0xFF 11 | #define OP_JMP_SEG 0x25 12 | 13 | #define OP_JMP_BYTE 0xEB 14 | #define OP_JMP_BYTE_SIZE 2 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | void check_thunks(unsigned char *dest, unsigned char *pc); 21 | 22 | //if dest is NULL, returns minimum number of bytes needed to be copied 23 | //if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs 24 | //http://www.devmaster.net/forums/showthread.php?t=2311 25 | int copy_bytes(unsigned char *func, unsigned char* dest, int required_len); 26 | 27 | //insert a specific JMP instruction at the given location 28 | void inject_jmp(void* src, void* dest); 29 | 30 | //fill a given block with NOPs 31 | void fill_nop(void* src, unsigned int len); 32 | 33 | //evaluate a JMP at the target 34 | void* eval_jump(void* src); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif //__ASM_H__ 41 | -------------------------------------------------------------------------------- /extension/configure.py: -------------------------------------------------------------------------------- 1 | # vim: set sts=2 ts=8 sw=2 tw=99 et: 2 | import sys 3 | from ambuild2 import run 4 | 5 | # Simple extensions do not need to modify this file. 6 | 7 | builder = run.PrepareBuild(sourcePath = sys.path[0]) 8 | 9 | builder.options.add_option('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None, 10 | help='Root search folder for HL2SDKs') 11 | builder.options.add_option('--mms-path', type=str, dest='mms_path', default=None, 12 | help='Path to Metamod:Source') 13 | builder.options.add_option('--sm-path', type=str, dest='sm_path', default=None, 14 | help='Path to SourceMod') 15 | builder.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', 16 | help='Enable debugging symbols') 17 | builder.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt', 18 | help='Enable optimization') 19 | builder.options.add_option('-s', '--sdks', default='all', dest='sdks', 20 | help='Build against specified SDKs; valid args are "all", "present", or ' 21 | 'comma-delimited list of engine names (default: %default)') 22 | 23 | builder.Configure() 24 | -------------------------------------------------------------------------------- /extension/defines.h: -------------------------------------------------------------------------------- 1 | 2 | #define MAXPLAYERS 65 3 | 4 | #define LEVEL_QUIETER -3500 5 | #define LEVEL_QUIET -2500 6 | #define LEVEL_LOUD 1000 7 | #define LEVEL_LOUDER 2500 8 | #define MAX_LEVELS 4 9 | 10 | #define MAX_FRAMEBUFFER_SAMPLES 480 11 | #define STEAM_HEADER_SIZE 12 12 | #define CRC_SIZE 4 13 | #define CHANNELS 1 14 | #define APPLICATION OPUS_APPLICATION_AUDIO 15 | #define BITRATE 32000 16 | #define MAX_FRAME_SIZE 6 * 960 17 | #define MAX_PACKET_SIZE 4096 -------------------------------------------------------------------------------- /extension/docker-compose.windows.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | extension-build-windows: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile.windows 8 | image: extension-build-windows 9 | volumes: 10 | - .:C:\extension 11 | working_dir: C:\extension 12 | -------------------------------------------------------------------------------- /extension/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | extension-build: 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | image: extension-build 9 | volumes: 10 | - .:/extension 11 | working_dir: /extension 12 | entrypoint: /extension/scripts/build.sh 13 | -------------------------------------------------------------------------------- /extension/extension.cpp: -------------------------------------------------------------------------------- 1 | #include "extension.h" 2 | #include "inetmessage.h" 3 | 4 | ConVar vm_enable("vm_enable", "1", FCVAR_NONE, "Enables voice manager"); 5 | DECL_DETOUR(SV_BroadcastVoiceData); 6 | 7 | VoiceManagerExt g_VoiceManager; // Global singleton for extension's main interface 8 | IGameConfig* g_pGameConf = nullptr; 9 | 10 | class CGameClient; 11 | class CFrameSnapshot; 12 | 13 | SMEXT_LINK(&g_VoiceManager); 14 | 15 | IBinTools* g_pBinTools = nullptr; 16 | ISDKTools* g_pSDKTools = nullptr; 17 | IServer* g_pServer = nullptr; 18 | 19 | struct VoiceOverride 20 | { 21 | std::vector clients; 22 | }; 23 | 24 | std::map> g_activeOverrides; 25 | std::map> m_userOverrides; 26 | std::map m_userGlobalOverrides; 27 | 28 | VoiceManagerClientState g_voiceManagerClientStates[MAXPLAYERS + 1]; 29 | 30 | void SendVoiceDataMsg(int fromClientSlot, IClient* pToClient, uint8_t* data, int nBytes, int64 xuid) 31 | { 32 | SVC_VoiceData msg; 33 | msg.m_bProximity = false; 34 | msg.m_nLength = nBytes * 8; 35 | msg.m_xuid = xuid; 36 | msg.m_nFromClient = fromClientSlot; 37 | msg.m_DataOut = data; 38 | pToClient->SendNetMsg(msg); 39 | }; 40 | 41 | DETOUR_DECL_STATIC4(SV_BroadcastVoiceData, void, IClient*, pClient, int, nBytes, uint8_t*, data, int64, xuid) 42 | { 43 | if (!vm_enable.GetBool()) 44 | { 45 | DETOUR_STATIC_CALL(SV_BroadcastVoiceData)(pClient, nBytes, data, xuid); 46 | return; 47 | } 48 | 49 | int fromClientSlot = pClient->GetPlayerSlot(); 50 | int fromClientIndex = pClient->GetPlayerSlot() + 1; 51 | 52 | // If there are no active overrides for this user, just broadcast the original data 53 | auto override = g_activeOverrides.find(fromClientIndex); 54 | if (override == g_activeOverrides.end()) 55 | { 56 | DETOUR_STATIC_CALL(SV_BroadcastVoiceData)(pClient, nBytes, data, xuid); 57 | return; 58 | } 59 | 60 | // Populate a map of potential recipients. 61 | // The criteria for a recipient: 62 | // - The client is found 63 | // - The client is connected 64 | // - The client is not a bot (does not include replay/source tv) 65 | // - The client can hear the player (accounts for mutes, voice loopback) 66 | std::map recipientMap; 67 | for (int client = 1; client <= playerhelpers->GetMaxClients(); client++) 68 | { 69 | IGamePlayer* pGamePlayer = playerhelpers->GetGamePlayer(client); 70 | if (pGamePlayer == nullptr || !pGamePlayer->IsConnected() || pGamePlayer->IsFakeClient()) 71 | { 72 | continue; 73 | } 74 | 75 | IClient* pToClient = g_pServer->GetClient(client - 1); 76 | if (pToClient == nullptr || !pToClient->IsHearingClient(fromClientSlot)) 77 | { 78 | continue; 79 | } 80 | 81 | recipientMap.insert({ client, pToClient }); 82 | } 83 | 84 | // Iterate over each volume level to determine if it has clients requesting it 85 | std::map overridingClients; 86 | for (int level = 0; level < MAX_LEVELS; level++) 87 | { 88 | // If the level has one or more clients requesting it, we need to re-encode the data at the specified level 89 | if (override->second[level].clients.size() > 0) 90 | { 91 | VoiceManager* vm = g_voiceManagerClientStates[override->first].GetVoiceManager(level); 92 | 93 | int nBytesOverride; 94 | uint8_t* newVoiceData = vm->OnBroadcastVoiceData(pClient, nBytes, data, &nBytesOverride); 95 | 96 | // Call CGameClient::SendNetMsg for each overriding client 97 | for (int client : override->second[level].clients) 98 | { 99 | // If the overriding client is not found, move on 100 | auto toClientPair = recipientMap.find(client); 101 | if (toClientPair == recipientMap.end()) 102 | { 103 | continue; 104 | } 105 | 106 | SendVoiceDataMsg(fromClientSlot, toClientPair->second, newVoiceData, nBytesOverride, xuid); 107 | 108 | // Remove the recipient from the map as we've already sent them the voice message 109 | recipientMap.erase(client); 110 | } 111 | 112 | delete[] newVoiceData; 113 | } 114 | } 115 | 116 | for (const auto& [index, client] : recipientMap) 117 | { 118 | SendVoiceDataMsg(fromClientSlot, client, data, nBytes, xuid); 119 | } 120 | } 121 | 122 | uint64_t GetClientSteamId(int client) 123 | { 124 | auto player = playerhelpers->GetGamePlayer(client); 125 | if (player == nullptr || !player->IsConnected()) 126 | { 127 | return -1; 128 | } 129 | 130 | return player->GetSteamId64(); 131 | } 132 | 133 | std::map GetClientSteamIdMap() 134 | { 135 | auto steamIdsToSlots = std::map(); 136 | for (int client = 1; client <= playerhelpers->GetMaxClients(); client++) 137 | { 138 | uint64_t steamId = GetClientSteamId(client); 139 | if (steamId > 0) 140 | { 141 | steamIdsToSlots.insert(std::pair(steamId, client)); 142 | } 143 | } 144 | 145 | return steamIdsToSlots; 146 | } 147 | 148 | void AddOverride(std::map>* overrides, int adjuster, int adjusted, int level) 149 | { 150 | auto newActiveOverride = overrides->find(adjusted); 151 | if (newActiveOverride == overrides->end()) 152 | { 153 | auto overrideLevels = std::map(); 154 | for (int i = 0; i < MAX_LEVELS; i++) 155 | { 156 | VoiceOverride vo; 157 | vo.clients = std::vector(); 158 | 159 | if (level == i) 160 | { 161 | vo.clients.push_back(adjuster); 162 | } 163 | 164 | overrideLevels.insert(std::pair{i, vo}); 165 | } 166 | 167 | overrides->insert(std::pair>{adjusted, overrideLevels}); 168 | } 169 | else 170 | { 171 | newActiveOverride->second.at(level).clients.push_back(adjuster); 172 | } 173 | } 174 | 175 | void RefreshActiveOverrides() 176 | { 177 | auto newActiveOverrides = std::map>(); 178 | auto steamIdsToSlots = GetClientSteamIdMap(); 179 | 180 | // Iterate over all active clients 181 | for (auto const& clientSteamIdPair : steamIdsToSlots) 182 | { 183 | int adjuster = clientSteamIdPair.second; 184 | 185 | for (auto const& otherClientSteamIdPair : steamIdsToSlots) 186 | { 187 | int adjusted = otherClientSteamIdPair.second; 188 | 189 | bool adjustmentMade = false; 190 | auto userOverride = m_userOverrides.find(clientSteamIdPair.first); 191 | if (userOverride != m_userOverrides.end()) 192 | { 193 | auto overrides = userOverride->second; 194 | for (auto override : overrides) 195 | { 196 | if (override.steamId == otherClientSteamIdPair.first) 197 | { 198 | // smutils->LogMessage(myself, "Adding individual override. Adjuster: %d, Adjusted: %d, Level: %d", adjuster, adjusted, override.level); 199 | AddOverride(&newActiveOverrides, adjuster, adjusted, override.level); 200 | adjustmentMade = true; 201 | break; 202 | } 203 | 204 | if (adjustmentMade) 205 | { 206 | break; 207 | } 208 | } 209 | } 210 | 211 | if (adjustmentMade) 212 | { 213 | continue; 214 | } 215 | 216 | auto globalOverride = m_userGlobalOverrides.find(clientSteamIdPair.first); 217 | if (globalOverride != m_userGlobalOverrides.end()) 218 | { 219 | // smutils->LogMessage(myself, "Adding global override. Adjuster: %d, Adjusted: %d, Level: %d", adjuster, adjusted, globalOverride->second); 220 | AddOverride(&newActiveOverrides, adjuster, adjusted, globalOverride->second); 221 | } 222 | } 223 | } 224 | 225 | g_activeOverrides = newActiveOverrides; 226 | } 227 | 228 | static cell_t OnGetClientOverride(IPluginContext* pContext, const cell_t* params) 229 | { 230 | if (!vm_enable.GetBool()) 231 | { 232 | return false; 233 | } 234 | 235 | int adjuster = params[1]; 236 | int adjusted = params[2]; 237 | 238 | uint64_t adjusterSteamId = GetClientSteamId(adjuster); 239 | 240 | auto overridePair = m_userOverrides.find(adjusterSteamId); 241 | // User has no adjustments, return -1 242 | if (overridePair == m_userOverrides.end()) 243 | { 244 | return -1; 245 | } 246 | 247 | uint64_t adjustedSteamId = GetClientSteamId(adjusted); 248 | for (auto override : overridePair->second) 249 | { 250 | if (override.steamId == adjustedSteamId) 251 | { 252 | return override.level; 253 | } 254 | } 255 | 256 | return -1; 257 | } 258 | 259 | static cell_t OnClearClientOverrides(IPluginContext* pContext, const cell_t* params) 260 | { 261 | if (!vm_enable.GetBool()) 262 | { 263 | return false; 264 | } 265 | 266 | int client = params[1]; 267 | 268 | uint64_t steamId = GetClientSteamId(client); 269 | if (m_userOverrides.find(steamId) != m_userOverrides.end()) 270 | { 271 | m_userOverrides.erase(steamId); 272 | } 273 | 274 | RefreshActiveOverrides(); 275 | 276 | return true; 277 | } 278 | 279 | static cell_t OnRefreshActiveOverrides(IPluginContext* pContext, const cell_t* params) 280 | { 281 | if (!vm_enable.GetBool()) 282 | { 283 | return false; 284 | } 285 | 286 | RefreshActiveOverrides(); 287 | return true; 288 | } 289 | 290 | static cell_t LoadPlayerAdjustment(IPluginContext* pContext, const cell_t* params) 291 | { 292 | if (!vm_enable.GetBool()) 293 | { 294 | return false; 295 | } 296 | 297 | char* adjustedSteamIdString; 298 | 299 | int adjuster = params[1]; 300 | pContext->LocalToString(params[2], &adjustedSteamIdString); 301 | 302 | int volume = params[3]; 303 | 304 | // If the volume is invalid, return false 305 | if (volume < 0) 306 | { 307 | return false; 308 | } 309 | 310 | uint64_t adjusterSteamId = GetClientSteamId(adjuster); 311 | uint64_t adjustedSteamId = std::stoull(adjustedSteamIdString); 312 | if (adjusterSteamId <= 0 || adjustedSteamId <= 0) 313 | { 314 | return false; 315 | } 316 | 317 | auto playerAdjusted = m_userOverrides.find(adjusterSteamId); 318 | 319 | UserOverride uo; 320 | uo.steamId = adjustedSteamId; 321 | uo.level = volume; 322 | 323 | if (playerAdjusted != m_userOverrides.end()) 324 | { 325 | bool existingFound = false; 326 | for (int i = 0; i < playerAdjusted->second.size(); i++) 327 | { 328 | if (playerAdjusted->second.at(i).steamId == adjustedSteamId) 329 | { 330 | playerAdjusted->second.at(i).level = uo.level; 331 | existingFound = true; 332 | break; 333 | } 334 | } 335 | 336 | // If we did not find an existing override, push it 337 | if (!existingFound) 338 | { 339 | playerAdjusted->second.push_back(uo); 340 | } 341 | } 342 | else 343 | { 344 | m_userOverrides.insert({ adjusterSteamId, std::vector{uo} }); 345 | } 346 | 347 | return true; 348 | } 349 | 350 | static cell_t OnPlayerAdjustVolume(IPluginContext* pContext, const cell_t* params) 351 | { 352 | if (!vm_enable.GetBool()) 353 | { 354 | return false; 355 | } 356 | 357 | int adjuster = params[1]; 358 | int adjusted = params[2]; 359 | int volume = params[3]; 360 | 361 | uint64_t adjusterSteamId = GetClientSteamId(adjuster); 362 | uint64_t adjustedSteamId = GetClientSteamId(adjusted); 363 | if (adjusterSteamId <= 0 || adjustedSteamId <= 0) 364 | { 365 | return false; 366 | } 367 | 368 | auto playerAdjusted = m_userOverrides.find(adjusterSteamId); 369 | 370 | bool isReset = volume < 0; 371 | if (isReset) 372 | { 373 | // Do nothing, they have no overrides and they're setting a preference as normal 374 | if (playerAdjusted == m_userOverrides.end()) 375 | { 376 | return true; 377 | } 378 | 379 | auto existingOverrides = playerAdjusted->second; 380 | 381 | for (int i = 0; i < existingOverrides.size(); i++) 382 | { 383 | if (existingOverrides.at(i).steamId == adjustedSteamId) 384 | { 385 | playerAdjusted->second.erase(playerAdjusted->second.begin() + i); 386 | break; 387 | } 388 | } 389 | } 390 | else 391 | { 392 | UserOverride uo; 393 | uo.steamId = adjustedSteamId; 394 | uo.level = volume; 395 | 396 | if (playerAdjusted != m_userOverrides.end()) 397 | { 398 | bool existingFound = false; 399 | for (int i = 0; i < playerAdjusted->second.size(); i++) 400 | { 401 | if (playerAdjusted->second.at(i).steamId == adjustedSteamId) 402 | { 403 | playerAdjusted->second.at(i).level = uo.level; 404 | existingFound = true; 405 | break; 406 | } 407 | } 408 | 409 | // If we did not find an existing override, push it 410 | if (!existingFound) 411 | { 412 | playerAdjusted->second.push_back(uo); 413 | } 414 | } 415 | else 416 | { 417 | m_userOverrides.insert({ adjusterSteamId, std::vector{uo} }); 418 | } 419 | } 420 | 421 | RefreshActiveOverrides(); 422 | 423 | return true; 424 | } 425 | 426 | static cell_t OnPlayerGlobalAdjust(IPluginContext* pContext, const cell_t* params) 427 | { 428 | if (!vm_enable.GetBool()) 429 | { 430 | return false; 431 | } 432 | 433 | int adjuster = params[1]; 434 | int volume = params[2]; 435 | 436 | uint64_t adjusterSteamId = GetClientSteamId(adjuster); 437 | if (adjusterSteamId <= 0 || adjusterSteamId <= 0) 438 | { 439 | return false; 440 | } 441 | 442 | auto globalOverride = m_userGlobalOverrides.find(adjusterSteamId); 443 | 444 | bool isReset = volume < 0; 445 | if (isReset) 446 | { 447 | // Do nothing, they have no overrides and they're setting a preference as normal 448 | if (globalOverride == m_userGlobalOverrides.end()) 449 | { 450 | return true; 451 | } 452 | 453 | m_userGlobalOverrides.erase(adjusterSteamId); 454 | } 455 | else 456 | { 457 | if (globalOverride != m_userGlobalOverrides.end()) 458 | { 459 | m_userGlobalOverrides[adjusterSteamId] = volume; 460 | } 461 | else 462 | { 463 | m_userGlobalOverrides.insert({ adjusterSteamId, volume }); 464 | } 465 | } 466 | 467 | RefreshActiveOverrides(); 468 | 469 | return true; 470 | } 471 | 472 | const sp_nativeinfo_t g_Natives[] = 473 | { 474 | {"LoadPlayerAdjustment", LoadPlayerAdjustment}, 475 | {"OnPlayerAdjustVolume", OnPlayerAdjustVolume}, 476 | {"RefreshActiveOverrides", OnRefreshActiveOverrides}, 477 | {"ClearClientOverrides", OnClearClientOverrides}, 478 | {"GetClientOverride", OnGetClientOverride}, 479 | {"OnPlayerGlobalAdjust", OnPlayerGlobalAdjust}, 480 | {nullptr, nullptr}, 481 | }; 482 | 483 | void VoiceManagerExt::SDK_OnAllLoaded() 484 | { 485 | SM_GET_LATE_IFACE(SDKTOOLS, g_pSDKTools); 486 | SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools); 487 | 488 | g_pServer = g_pSDKTools->GetIServer(); 489 | } 490 | 491 | bool VoiceManagerExt::SDK_OnLoad(char* error, size_t maxlength, bool late) 492 | { 493 | sharesys->AddDependency(myself, "sdktools.ext", true, true); 494 | sharesys->AddDependency(myself, "bintools.ext", true, true); 495 | plsys->AddPluginsListener(this); 496 | sharesys->AddNatives(myself, g_Natives); 497 | 498 | char conf_error[255]; 499 | if (!gameconfs->LoadGameConfigFile("voicemanager", &g_pGameConf, conf_error, sizeof(conf_error))) 500 | { 501 | if (conf_error[0]) 502 | { 503 | snprintf(error, maxlength, "Could not read config file voicemanager.txt: %s", conf_error); 504 | } 505 | 506 | return false; 507 | } 508 | 509 | CDetourManager::Init(smutils->GetScriptingEngine(), g_pGameConf); 510 | 511 | bool bDetoursInited = false; 512 | CREATE_DETOUR_STATIC(SV_BroadcastVoiceData, "SV_BroadcastVoiceData", bDetoursInited); 513 | 514 | for (int i = 1; i <= playerhelpers->GetMaxClients(); i++) 515 | { 516 | g_voiceManagerClientStates[i] = VoiceManagerClientState(); 517 | } 518 | 519 | return true; 520 | } 521 | 522 | bool VoiceManagerExt::RegisterConCommandBase(ConCommandBase* pCommand) 523 | { 524 | META_REGCVAR(pCommand); 525 | return true; 526 | } 527 | 528 | bool VoiceManagerExt::SDK_OnMetamodLoad(ISmmAPI* ismm, char* error, size_t maxlen, bool late) 529 | { 530 | GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION); 531 | ConVar_Register(0, this); 532 | 533 | return true; 534 | } 535 | -------------------------------------------------------------------------------- /extension/extension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ 4 | #define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "smsdk_ext.h" 14 | #include "defines.h" 15 | #include "CDetour/detours.h" 16 | #include "voicemanagerclientstate.h" 17 | 18 | extern ConVar vm_enable; 19 | 20 | struct ActiveOverride { 21 | int client; 22 | int level; 23 | }; 24 | 25 | struct UserOverride { 26 | uint64_t steamId; 27 | int level; 28 | }; 29 | 30 | class VoiceManagerExt : public SDKExtension, public IConCommandBaseAccessor, public IPluginsListener 31 | { 32 | public: 33 | virtual bool SDK_OnLoad(char* error, size_t maxlen, bool late); 34 | virtual void SDK_OnAllLoaded(); 35 | virtual bool SDK_OnMetamodLoad(ISmmAPI* ismm, char* error, size_t maxlength, bool late); 36 | bool RegisterConCommandBase(ConCommandBase* pCommand); 37 | }; 38 | 39 | #endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ 40 | -------------------------------------------------------------------------------- /extension/include/celt/arch.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2003-2008 Jean-Marc Valin 2 | Copyright (c) 2007-2008 CSIRO 3 | Copyright (c) 2007-2009 Xiph.Org Foundation 4 | Written by Jean-Marc Valin */ 5 | /** 6 | @file arch.h 7 | @brief Various architecture definitions for CELT 8 | */ 9 | /* 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions 12 | are met: 13 | 14 | - Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | 17 | - Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 25 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #ifndef ARCH_H 35 | #define ARCH_H 36 | 37 | #include "opus_types.h" 38 | #include "opus_defines.h" 39 | 40 | # if !defined(__GNUC_PREREQ) 41 | # if defined(__GNUC__)&&defined(__GNUC_MINOR__) 42 | # define __GNUC_PREREQ(_maj,_min) \ 43 | ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) 44 | # else 45 | # define __GNUC_PREREQ(_maj,_min) 0 46 | # endif 47 | # endif 48 | 49 | #if OPUS_GNUC_PREREQ(3, 0) 50 | #define opus_likely(x) (__builtin_expect(!!(x), 1)) 51 | #define opus_unlikely(x) (__builtin_expect(!!(x), 0)) 52 | #else 53 | #define opus_likely(x) (!!(x)) 54 | #define opus_unlikely(x) (!!(x)) 55 | #endif 56 | 57 | #define CELT_SIG_SCALE 32768.f 58 | 59 | #define CELT_FATAL(str) celt_fatal(str, __FILE__, __LINE__); 60 | 61 | #if defined(ENABLE_ASSERTIONS) || defined(ENABLE_HARDENING) 62 | #ifdef __GNUC__ 63 | __attribute__((noreturn)) 64 | #endif 65 | void celt_fatal(const char *str, const char *file, int line); 66 | 67 | #if defined(CELT_C) && !defined(OVERRIDE_celt_fatal) 68 | #include 69 | #include 70 | #ifdef __GNUC__ 71 | __attribute__((noreturn)) 72 | #endif 73 | void celt_fatal(const char *str, const char *file, int line) 74 | { 75 | fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); 76 | abort(); 77 | } 78 | #endif 79 | 80 | #define celt_assert(cond) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond);}} 81 | #define celt_assert2(cond, message) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond "\n" message);}} 82 | #define MUST_SUCCEED(call) celt_assert((call) == OPUS_OK) 83 | #else 84 | #define celt_assert(cond) 85 | #define celt_assert2(cond, message) 86 | #define MUST_SUCCEED(call) do {if((call) != OPUS_OK) {RESTORE_STACK; return OPUS_INTERNAL_ERROR;} } while (0) 87 | #endif 88 | 89 | #if defined(ENABLE_ASSERTIONS) 90 | #define celt_sig_assert(cond) {if (!(cond)) {CELT_FATAL("signal assertion failed: " #cond);}} 91 | #else 92 | #define celt_sig_assert(cond) 93 | #endif 94 | 95 | #define IMUL32(a,b) ((a)*(b)) 96 | 97 | #define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ 98 | #define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ 99 | #define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ 100 | #define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ 101 | #define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ 102 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ 103 | #define UADD32(a,b) ((a)+(b)) 104 | #define USUB32(a,b) ((a)-(b)) 105 | 106 | /* Set this if opus_int64 is a native type of the CPU. */ 107 | /* Assume that all LP64 architectures have fast 64-bit types; also x86_64 108 | (which can be ILP32 for x32) and Win64 (which is LLP64). */ 109 | #if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64) 110 | #define OPUS_FAST_INT64 1 111 | #else 112 | #define OPUS_FAST_INT64 0 113 | #endif 114 | 115 | #define PRINT_MIPS(file) 116 | 117 | #ifdef FIXED_POINT 118 | 119 | typedef opus_int16 opus_val16; 120 | typedef opus_int32 opus_val32; 121 | typedef opus_int64 opus_val64; 122 | 123 | typedef opus_val32 celt_sig; 124 | typedef opus_val16 celt_norm; 125 | typedef opus_val32 celt_ener; 126 | 127 | #define celt_isnan(x) 0 128 | 129 | #define Q15ONE 32767 130 | 131 | #define SIG_SHIFT 12 132 | /* Safe saturation value for 32-bit signals. Should be less than 133 | 2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/ 134 | #define SIG_SAT (300000000) 135 | 136 | #define NORM_SCALING 16384 137 | 138 | #define DB_SHIFT 10 139 | 140 | #define EPSILON 1 141 | #define VERY_SMALL 0 142 | #define VERY_LARGE16 ((opus_val16)32767) 143 | #define Q15_ONE ((opus_val16)32767) 144 | 145 | #define SCALEIN(a) (a) 146 | #define SCALEOUT(a) (a) 147 | 148 | #define ABS16(x) ((x) < 0 ? (-(x)) : (x)) 149 | #define ABS32(x) ((x) < 0 ? (-(x)) : (x)) 150 | 151 | static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { 152 | return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; 153 | } 154 | 155 | #ifdef FIXED_DEBUG 156 | #include "fixed_debug.h" 157 | #else 158 | 159 | #include "fixed_generic.h" 160 | 161 | #ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR 162 | #include "arm/fixed_arm64.h" 163 | #elif defined (OPUS_ARM_INLINE_EDSP) 164 | #include "arm/fixed_armv5e.h" 165 | #elif defined (OPUS_ARM_INLINE_ASM) 166 | #include "arm/fixed_armv4.h" 167 | #elif defined (BFIN_ASM) 168 | #include "fixed_bfin.h" 169 | #elif defined (TI_C5X_ASM) 170 | #include "fixed_c5x.h" 171 | #elif defined (TI_C6X_ASM) 172 | #include "fixed_c6x.h" 173 | #endif 174 | 175 | #endif 176 | 177 | #else /* FIXED_POINT */ 178 | 179 | typedef float opus_val16; 180 | typedef float opus_val32; 181 | typedef float opus_val64; 182 | 183 | typedef float celt_sig; 184 | typedef float celt_norm; 185 | typedef float celt_ener; 186 | 187 | #ifdef FLOAT_APPROX 188 | /* This code should reliably detect NaN/inf even when -ffast-math is used. 189 | Assumes IEEE 754 format. */ 190 | static OPUS_INLINE int celt_isnan(float x) 191 | { 192 | union {float f; opus_uint32 i;} in; 193 | in.f = x; 194 | return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0; 195 | } 196 | #else 197 | #ifdef __FAST_MATH__ 198 | #error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input 199 | #endif 200 | #define celt_isnan(x) ((x)!=(x)) 201 | #endif 202 | 203 | #define Q15ONE 1.0f 204 | 205 | #define NORM_SCALING 1.f 206 | 207 | #define EPSILON 1e-15f 208 | #define VERY_SMALL 1e-30f 209 | #define VERY_LARGE16 1e15f 210 | #define Q15_ONE ((opus_val16)1.f) 211 | 212 | /* This appears to be the same speed as C99's fabsf() but it's more portable. */ 213 | #define ABS16(x) ((float)fabs(x)) 214 | #define ABS32(x) ((float)fabs(x)) 215 | 216 | #define QCONST16(x,bits) (x) 217 | #define QCONST32(x,bits) (x) 218 | 219 | #define NEG16(x) (-(x)) 220 | #define NEG32(x) (-(x)) 221 | #define NEG32_ovflw(x) (-(x)) 222 | #define EXTRACT16(x) (x) 223 | #define EXTEND32(x) (x) 224 | #define SHR16(a,shift) (a) 225 | #define SHL16(a,shift) (a) 226 | #define SHR32(a,shift) (a) 227 | #define SHL32(a,shift) (a) 228 | #define PSHR32(a,shift) (a) 229 | #define VSHR32(a,shift) (a) 230 | 231 | #define PSHR(a,shift) (a) 232 | #define SHR(a,shift) (a) 233 | #define SHL(a,shift) (a) 234 | #define SATURATE(x,a) (x) 235 | #define SATURATE16(x) (x) 236 | 237 | #define ROUND16(a,shift) (a) 238 | #define SROUND16(a,shift) (a) 239 | #define HALF16(x) (.5f*(x)) 240 | #define HALF32(x) (.5f*(x)) 241 | 242 | #define ADD16(a,b) ((a)+(b)) 243 | #define SUB16(a,b) ((a)-(b)) 244 | #define ADD32(a,b) ((a)+(b)) 245 | #define SUB32(a,b) ((a)-(b)) 246 | #define ADD32_ovflw(a,b) ((a)+(b)) 247 | #define SUB32_ovflw(a,b) ((a)-(b)) 248 | #define MULT16_16_16(a,b) ((a)*(b)) 249 | #define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b)) 250 | #define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b)) 251 | 252 | #define MULT16_32_Q15(a,b) ((a)*(b)) 253 | #define MULT16_32_Q16(a,b) ((a)*(b)) 254 | 255 | #define MULT32_32_Q31(a,b) ((a)*(b)) 256 | 257 | #define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) 258 | #define MAC16_32_Q16(c,a,b) ((c)+(a)*(b)) 259 | 260 | #define MULT16_16_Q11_32(a,b) ((a)*(b)) 261 | #define MULT16_16_Q11(a,b) ((a)*(b)) 262 | #define MULT16_16_Q13(a,b) ((a)*(b)) 263 | #define MULT16_16_Q14(a,b) ((a)*(b)) 264 | #define MULT16_16_Q15(a,b) ((a)*(b)) 265 | #define MULT16_16_P15(a,b) ((a)*(b)) 266 | #define MULT16_16_P13(a,b) ((a)*(b)) 267 | #define MULT16_16_P14(a,b) ((a)*(b)) 268 | #define MULT16_32_P16(a,b) ((a)*(b)) 269 | 270 | #define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) 271 | #define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) 272 | 273 | #define SCALEIN(a) ((a)*CELT_SIG_SCALE) 274 | #define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) 275 | 276 | #define SIG2WORD16(x) (x) 277 | 278 | #endif /* !FIXED_POINT */ 279 | 280 | #ifndef GLOBAL_STACK_SIZE 281 | #ifdef FIXED_POINT 282 | #define GLOBAL_STACK_SIZE 120000 283 | #else 284 | #define GLOBAL_STACK_SIZE 120000 285 | #endif 286 | #endif 287 | 288 | #endif /* ARCH_H */ 289 | -------------------------------------------------------------------------------- /extension/include/celt/celt.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2008 CSIRO 2 | Copyright (c) 2007-2009 Xiph.Org Foundation 3 | Copyright (c) 2008 Gregory Maxwell 4 | Written by Jean-Marc Valin and Gregory Maxwell */ 5 | /** 6 | @file celt.h 7 | @brief Contains all the functions for encoding and decoding audio 8 | */ 9 | 10 | /* 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions 13 | are met: 14 | 15 | - Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 18 | - Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the distribution. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 26 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef CELT_H 36 | #define CELT_H 37 | 38 | #include "opus_types.h" 39 | #include "opus_defines.h" 40 | #include "opus_custom.h" 41 | #include "entenc.h" 42 | #include "entdec.h" 43 | #include "arch.h" 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | #define CELTEncoder OpusCustomEncoder 50 | #define CELTDecoder OpusCustomDecoder 51 | #define CELTMode OpusCustomMode 52 | 53 | #define LEAK_BANDS 19 54 | 55 | typedef struct { 56 | int valid; 57 | float tonality; 58 | float tonality_slope; 59 | float noisiness; 60 | float activity; 61 | float music_prob; 62 | float music_prob_min; 63 | float music_prob_max; 64 | int bandwidth; 65 | float activity_probability; 66 | float max_pitch_ratio; 67 | /* Store as Q6 char to save space. */ 68 | unsigned char leak_boost[LEAK_BANDS]; 69 | } AnalysisInfo; 70 | 71 | typedef struct { 72 | int signalType; 73 | int offset; 74 | } SILKInfo; 75 | 76 | #define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) 77 | 78 | #define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr))) 79 | 80 | #define __celt_check_silkinfo_ptr(ptr) ((ptr) + ((ptr) - (const SILKInfo*)(ptr))) 81 | 82 | /* Encoder/decoder Requests */ 83 | 84 | 85 | #define CELT_SET_PREDICTION_REQUEST 10002 86 | /** Controls the use of interframe prediction. 87 | 0=Independent frames 88 | 1=Short term interframe prediction allowed 89 | 2=Long term prediction allowed 90 | */ 91 | #define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x) 92 | 93 | #define CELT_SET_INPUT_CLIPPING_REQUEST 10004 94 | #define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x) 95 | 96 | #define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 97 | #define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x) 98 | 99 | #define CELT_SET_CHANNELS_REQUEST 10008 100 | #define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x) 101 | 102 | 103 | /* Internal */ 104 | #define CELT_SET_START_BAND_REQUEST 10010 105 | #define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x) 106 | 107 | #define CELT_SET_END_BAND_REQUEST 10012 108 | #define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x) 109 | 110 | #define CELT_GET_MODE_REQUEST 10015 111 | /** Get the CELTMode used by an encoder or decoder */ 112 | #define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x) 113 | 114 | #define CELT_SET_SIGNALLING_REQUEST 10016 115 | #define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x) 116 | 117 | #define CELT_SET_TONALITY_REQUEST 10018 118 | #define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x) 119 | #define CELT_SET_TONALITY_SLOPE_REQUEST 10020 120 | #define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x) 121 | 122 | #define CELT_SET_ANALYSIS_REQUEST 10022 123 | #define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x) 124 | 125 | #define OPUS_SET_LFE_REQUEST 10024 126 | #define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x) 127 | 128 | #define OPUS_SET_ENERGY_MASK_REQUEST 10026 129 | #define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x) 130 | 131 | #define CELT_SET_SILK_INFO_REQUEST 10028 132 | #define CELT_SET_SILK_INFO(x) CELT_SET_SILK_INFO_REQUEST, __celt_check_silkinfo_ptr(x) 133 | 134 | /* Encoder stuff */ 135 | 136 | int celt_encoder_get_size(int channels); 137 | 138 | int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); 139 | 140 | int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, 141 | int arch); 142 | 143 | 144 | 145 | /* Decoder stuff */ 146 | 147 | int celt_decoder_get_size(int channels); 148 | 149 | 150 | int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels); 151 | 152 | int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, 153 | int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum); 154 | 155 | #define celt_encoder_ctl opus_custom_encoder_ctl 156 | #define celt_decoder_ctl opus_custom_decoder_ctl 157 | 158 | 159 | #ifdef CUSTOM_MODES 160 | #define OPUS_CUSTOM_NOSTATIC 161 | #else 162 | #define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE 163 | #endif 164 | 165 | static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; 166 | /* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ 167 | static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; 168 | 169 | static const unsigned char tapset_icdf[3]={2,1,0}; 170 | 171 | #ifdef CUSTOM_MODES 172 | static const unsigned char toOpusTable[20] = { 173 | 0xE0, 0xE8, 0xF0, 0xF8, 174 | 0xC0, 0xC8, 0xD0, 0xD8, 175 | 0xA0, 0xA8, 0xB0, 0xB8, 176 | 0x00, 0x00, 0x00, 0x00, 177 | 0x80, 0x88, 0x90, 0x98, 178 | }; 179 | 180 | static const unsigned char fromOpusTable[16] = { 181 | 0x80, 0x88, 0x90, 0x98, 182 | 0x40, 0x48, 0x50, 0x58, 183 | 0x20, 0x28, 0x30, 0x38, 184 | 0x00, 0x08, 0x10, 0x18 185 | }; 186 | 187 | static OPUS_INLINE int toOpus(unsigned char c) 188 | { 189 | int ret=0; 190 | if (c<0xA0) 191 | ret = toOpusTable[c>>3]; 192 | if (ret == 0) 193 | return -1; 194 | else 195 | return ret|(c&0x7); 196 | } 197 | 198 | static OPUS_INLINE int fromOpus(unsigned char c) 199 | { 200 | if (c<0x80) 201 | return -1; 202 | else 203 | return fromOpusTable[(c>>3)-16] | (c&0x7); 204 | } 205 | #endif /* CUSTOM_MODES */ 206 | 207 | #define COMBFILTER_MAXPERIOD 1024 208 | #define COMBFILTER_MINPERIOD 15 209 | 210 | extern const signed char tf_select_table[4][8]; 211 | 212 | #if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) 213 | void validate_celt_decoder(CELTDecoder *st); 214 | #define VALIDATE_CELT_DECODER(st) validate_celt_decoder(st) 215 | #else 216 | #define VALIDATE_CELT_DECODER(st) 217 | #endif 218 | 219 | int resampling_factor(opus_int32 rate); 220 | 221 | void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp, 222 | int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip); 223 | 224 | void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, 225 | opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, 226 | const opus_val16 *window, int overlap, int arch); 227 | 228 | #ifdef NON_STATIC_COMB_FILTER_CONST_C 229 | void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, 230 | opus_val16 g10, opus_val16 g11, opus_val16 g12); 231 | #endif 232 | 233 | #ifndef OVERRIDE_COMB_FILTER_CONST 234 | # define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \ 235 | ((void)(arch),comb_filter_const_c(y, x, T, N, g10, g11, g12)) 236 | #endif 237 | 238 | void init_caps(const CELTMode *m,int *cap,int LM,int C); 239 | 240 | #ifdef RESYNTH 241 | void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem); 242 | void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[], 243 | opus_val16 *oldBandE, int start, int effEnd, int C, int CC, int isTransient, 244 | int LM, int downsample, int silence); 245 | #endif 246 | 247 | #ifdef __cplusplus 248 | } 249 | #endif 250 | 251 | #endif /* CELT_H */ 252 | -------------------------------------------------------------------------------- /extension/include/celt/ecintrin.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2003-2008 Timothy B. Terriberry 2 | Copyright (c) 2008 Xiph.Org Foundation */ 3 | /* 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /*Some common macros for potential platform-specific optimization.*/ 29 | #include "opus_types.h" 30 | #include 31 | #include 32 | #include "arch.h" 33 | #if !defined(_ecintrin_H) 34 | # define _ecintrin_H (1) 35 | 36 | /*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly 37 | versions of these functions which can substantially improve performance. 38 | We define macros for them to allow easy incorporation of these non-ANSI 39 | features.*/ 40 | 41 | /*Modern gcc (4.x) can compile the naive versions of min and max with cmov if 42 | given an appropriate architecture, but the branchless bit-twiddling versions 43 | are just as fast, and do not require any special target architecture. 44 | Earlier gcc versions (3.x) compiled both code to the same assembly 45 | instructions, because of the way they represented ((_b)>(_a)) internally.*/ 46 | # define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) 47 | 48 | /*Count leading zeros. 49 | This macro should only be used for implementing ec_ilog(), if it is defined. 50 | All other code should use EC_ILOG() instead.*/ 51 | #if defined(_MSC_VER) && (_MSC_VER >= 1400) 52 | # include 53 | /*In _DEBUG mode this is not an intrinsic by default.*/ 54 | # pragma intrinsic(_BitScanReverse) 55 | 56 | static __inline int ec_bsr(unsigned long _x){ 57 | unsigned long ret; 58 | _BitScanReverse(&ret,_x); 59 | return (int)ret; 60 | } 61 | # define EC_CLZ0 (1) 62 | # define EC_CLZ(_x) (-ec_bsr(_x)) 63 | #elif defined(ENABLE_TI_DSPLIB) 64 | # include "dsplib.h" 65 | # define EC_CLZ0 (31) 66 | # define EC_CLZ(_x) (_lnorm(_x)) 67 | #elif __GNUC_PREREQ(3,4) 68 | # if INT_MAX>=2147483647 69 | # define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) 70 | # define EC_CLZ(_x) (__builtin_clz(_x)) 71 | # elif LONG_MAX>=2147483647L 72 | # define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) 73 | # define EC_CLZ(_x) (__builtin_clzl(_x)) 74 | # endif 75 | #endif 76 | 77 | #if defined(EC_CLZ) 78 | /*Note that __builtin_clz is not defined when _x==0, according to the gcc 79 | documentation (and that of the BSR instruction that implements it on x86). 80 | The majority of the time we can never pass it zero. 81 | When we need to, it can be special cased.*/ 82 | # define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) 83 | #else 84 | int ec_ilog(opus_uint32 _v); 85 | # define EC_ILOG(_x) (ec_ilog(_x)) 86 | #endif 87 | #endif 88 | -------------------------------------------------------------------------------- /extension/include/celt/entcode.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2001-2011 Timothy B. Terriberry 2 | Copyright (c) 2008-2009 Xiph.Org Foundation */ 3 | /* 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "opus_types.h" 29 | #include "opus_defines.h" 30 | 31 | #if !defined(_entcode_H) 32 | # define _entcode_H (1) 33 | # include 34 | # include 35 | # include "ecintrin.h" 36 | 37 | extern const opus_uint32 SMALL_DIV_TABLE[129]; 38 | 39 | #ifdef OPUS_ARM_ASM 40 | #define USE_SMALL_DIV_TABLE 41 | #endif 42 | 43 | /*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a 44 | larger type, you can speed up the decoder by using it here.*/ 45 | typedef opus_uint32 ec_window; 46 | typedef struct ec_ctx ec_ctx; 47 | typedef struct ec_ctx ec_enc; 48 | typedef struct ec_ctx ec_dec; 49 | 50 | # define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) 51 | 52 | /*The number of bits to use for the range-coded part of unsigned integers.*/ 53 | # define EC_UINT_BITS (8) 54 | 55 | /*The resolution of fractional-precision bit usage measurements, i.e., 56 | 3 => 1/8th bits.*/ 57 | # define BITRES 3 58 | 59 | /*The entropy encoder/decoder context. 60 | We use the same structure for both, so that common functions like ec_tell() 61 | can be used on either one.*/ 62 | struct ec_ctx{ 63 | /*Buffered input/output.*/ 64 | unsigned char *buf; 65 | /*The size of the buffer.*/ 66 | opus_uint32 storage; 67 | /*The offset at which the last byte containing raw bits was read/written.*/ 68 | opus_uint32 end_offs; 69 | /*Bits that will be read from/written at the end.*/ 70 | ec_window end_window; 71 | /*Number of valid bits in end_window.*/ 72 | int nend_bits; 73 | /*The total number of whole bits read/written. 74 | This does not include partial bits currently in the range coder.*/ 75 | int nbits_total; 76 | /*The offset at which the next range coder byte will be read/written.*/ 77 | opus_uint32 offs; 78 | /*The number of values in the current range.*/ 79 | opus_uint32 rng; 80 | /*In the decoder: the difference between the top of the current range and 81 | the input value, minus one. 82 | In the encoder: the low end of the current range.*/ 83 | opus_uint32 val; 84 | /*In the decoder: the saved normalization factor from ec_decode(). 85 | In the encoder: the number of oustanding carry propagating symbols.*/ 86 | opus_uint32 ext; 87 | /*A buffered input/output symbol, awaiting carry propagation.*/ 88 | int rem; 89 | /*Nonzero if an error occurred.*/ 90 | int error; 91 | }; 92 | 93 | static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){ 94 | return _this->offs; 95 | } 96 | 97 | static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){ 98 | return _this->buf; 99 | } 100 | 101 | static OPUS_INLINE int ec_get_error(ec_ctx *_this){ 102 | return _this->error; 103 | } 104 | 105 | /*Returns the number of bits "used" by the encoded or decoded symbols so far. 106 | This same number can be computed in either the encoder or the decoder, and is 107 | suitable for making coding decisions. 108 | Return: The number of bits. 109 | This will always be slightly larger than the exact value (e.g., all 110 | rounding error is in the positive direction).*/ 111 | static OPUS_INLINE int ec_tell(ec_ctx *_this){ 112 | return _this->nbits_total-EC_ILOG(_this->rng); 113 | } 114 | 115 | /*Returns the number of bits "used" by the encoded or decoded symbols so far. 116 | This same number can be computed in either the encoder or the decoder, and is 117 | suitable for making coding decisions. 118 | Return: The number of bits scaled by 2**BITRES. 119 | This will always be slightly larger than the exact value (e.g., all 120 | rounding error is in the positive direction).*/ 121 | opus_uint32 ec_tell_frac(ec_ctx *_this); 122 | 123 | /* Tested exhaustively for all n and for 1<=d<=256 */ 124 | static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) { 125 | celt_sig_assert(d>0); 126 | #ifdef USE_SMALL_DIV_TABLE 127 | if (d>256) 128 | return n/d; 129 | else { 130 | opus_uint32 t, q; 131 | t = EC_ILOG(d&-d); 132 | q = (opus_uint64)SMALL_DIV_TABLE[d>>t]*(n>>(t-1))>>32; 133 | return q+(n-q*d >= d); 134 | } 135 | #else 136 | return n/d; 137 | #endif 138 | } 139 | 140 | static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) { 141 | celt_sig_assert(d>0); 142 | #ifdef USE_SMALL_DIV_TABLE 143 | if (n<0) 144 | return -(opus_int32)celt_udiv(-n, d); 145 | else 146 | return celt_udiv(n, d); 147 | #else 148 | return n/d; 149 | #endif 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /extension/include/celt/entdec.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2001-2011 Timothy B. Terriberry 2 | Copyright (c) 2008-2009 Xiph.Org Foundation */ 3 | /* 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #if !defined(_entdec_H) 29 | # define _entdec_H (1) 30 | # include 31 | # include "entcode.h" 32 | 33 | /*Initializes the decoder. 34 | _buf: The input buffer to use. 35 | Return: 0 on success, or a negative value on error.*/ 36 | void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage); 37 | 38 | /*Calculates the cumulative frequency for the next symbol. 39 | This can then be fed into the probability model to determine what that 40 | symbol is, and the additional frequency information required to advance to 41 | the next symbol. 42 | This function cannot be called more than once without a corresponding call to 43 | ec_dec_update(), or decoding will not proceed correctly. 44 | _ft: The total frequency of the symbols in the alphabet the next symbol was 45 | encoded with. 46 | Return: A cumulative frequency representing the encoded symbol. 47 | If the cumulative frequency of all the symbols before the one that 48 | was encoded was fl, and the cumulative frequency of all the symbols 49 | up to and including the one encoded is fh, then the returned value 50 | will fall in the range [fl,fh).*/ 51 | unsigned ec_decode(ec_dec *_this,unsigned _ft); 52 | 53 | /*Equivalent to ec_decode() with _ft==1<<_bits.*/ 54 | unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); 55 | 56 | /*Advance the decoder past the next symbol using the frequency information the 57 | symbol was encoded with. 58 | Exactly one call to ec_decode() must have been made so that all necessary 59 | intermediate calculations are performed. 60 | _fl: The cumulative frequency of all symbols that come before the symbol 61 | decoded. 62 | _fh: The cumulative frequency of all symbols up to and including the symbol 63 | decoded. 64 | Together with _fl, this defines the range [_fl,_fh) in which the value 65 | returned above must fall. 66 | _ft: The total frequency of the symbols in the alphabet the symbol decoded 67 | was encoded in. 68 | This must be the same as passed to the preceding call to ec_decode().*/ 69 | void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); 70 | 71 | /* Decode a bit that has a 1/(1<<_logp) probability of being a one */ 72 | int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); 73 | 74 | /*Decodes a symbol given an "inverse" CDF table. 75 | No call to ec_dec_update() is necessary after this call. 76 | _icdf: The "inverse" CDF, such that symbol s falls in the range 77 | [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. 78 | The values must be monotonically non-increasing, and the last value 79 | must be 0. 80 | _ftb: The number of bits of precision in the cumulative distribution. 81 | Return: The decoded symbol s.*/ 82 | int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); 83 | 84 | /*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. 85 | The bits must have been encoded with ec_enc_uint(). 86 | No call to ec_dec_update() is necessary after this call. 87 | _ft: The number of integers that can be decoded (one more than the max). 88 | This must be at least 2, and no more than 2**32-1. 89 | Return: The decoded bits.*/ 90 | opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); 91 | 92 | /*Extracts a sequence of raw bits from the stream. 93 | The bits must have been encoded with ec_enc_bits(). 94 | No call to ec_dec_update() is necessary after this call. 95 | _ftb: The number of bits to extract. 96 | This must be between 0 and 25, inclusive. 97 | Return: The decoded bits.*/ 98 | opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /extension/include/celt/entenc.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2001-2011 Timothy B. Terriberry 2 | Copyright (c) 2008-2009 Xiph.Org Foundation */ 3 | /* 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #if !defined(_entenc_H) 29 | # define _entenc_H (1) 30 | # include 31 | # include "entcode.h" 32 | 33 | /*Initializes the encoder. 34 | _buf: The buffer to store output bytes in. 35 | _size: The size of the buffer, in chars.*/ 36 | void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size); 37 | /*Encodes a symbol given its frequency information. 38 | The frequency information must be discernable by the decoder, assuming it 39 | has read only the previous symbols from the stream. 40 | It is allowable to change the frequency information, or even the entire 41 | source alphabet, so long as the decoder can tell from the context of the 42 | previously encoded information that it is supposed to do so as well. 43 | _fl: The cumulative frequency of all symbols that come before the one to be 44 | encoded. 45 | _fh: The cumulative frequency of all symbols up to and including the one to 46 | be encoded. 47 | Together with _fl, this defines the range [_fl,_fh) in which the 48 | decoded value will fall. 49 | _ft: The sum of the frequencies of all the symbols*/ 50 | void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); 51 | 52 | /*Equivalent to ec_encode() with _ft==1<<_bits.*/ 53 | void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); 54 | 55 | /* Encode a bit that has a 1/(1<<_logp) probability of being a one */ 56 | void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); 57 | 58 | /*Encodes a symbol given an "inverse" CDF table. 59 | _s: The index of the symbol to encode. 60 | _icdf: The "inverse" CDF, such that symbol _s falls in the range 61 | [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. 62 | The values must be monotonically non-increasing, and the last value 63 | must be 0. 64 | _ftb: The number of bits of precision in the cumulative distribution.*/ 65 | void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); 66 | 67 | /*Encodes a raw unsigned integer in the stream. 68 | _fl: The integer to encode. 69 | _ft: The number of integers that can be encoded (one more than the max). 70 | This must be at least 2, and no more than 2**32-1.*/ 71 | void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft); 72 | 73 | /*Encodes a sequence of raw bits in the stream. 74 | _fl: The bits to encode. 75 | _ftb: The number of bits to encode. 76 | This must be between 1 and 25, inclusive.*/ 77 | void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb); 78 | 79 | /*Overwrites a few bits at the very start of an existing stream, after they 80 | have already been encoded. 81 | This makes it possible to have a few flags up front, where it is easy for 82 | decoders to access them without parsing the whole stream, even if their 83 | values are not determined until late in the encoding process, without having 84 | to buffer all the intermediate symbols in the encoder. 85 | In order for this to work, at least _nbits bits must have already been 86 | encoded using probabilities that are an exact power of two. 87 | The encoder can verify the number of encoded bits is sufficient, but cannot 88 | check this latter condition. 89 | _val: The bits to encode (in the least _nbits significant bits). 90 | They will be decoded in order from most-significant to least. 91 | _nbits: The number of bits to overwrite. 92 | This must be no more than 8.*/ 93 | void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); 94 | 95 | /*Compacts the data to fit in the target size. 96 | This moves up the raw bits at the end of the current buffer so they are at 97 | the end of the new buffer size. 98 | The caller must ensure that the amount of data that's already been written 99 | will fit in the new size. 100 | _size: The number of bytes in the new buffer. 101 | This must be large enough to contain the bits already written, and 102 | must be no larger than the existing size.*/ 103 | void ec_enc_shrink(ec_enc *_this,opus_uint32 _size); 104 | 105 | /*Indicates that there are no more symbols to encode. 106 | All reamining output bytes are flushed to the output buffer. 107 | ec_enc_init() must be called before the encoder can be used again.*/ 108 | void ec_enc_done(ec_enc *_this); 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /extension/include/celt/mathops.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2002-2008 Jean-Marc Valin 2 | Copyright (c) 2007-2008 CSIRO 3 | Copyright (c) 2007-2009 Xiph.Org Foundation 4 | Written by Jean-Marc Valin */ 5 | /** 6 | @file mathops.h 7 | @brief Various math functions 8 | */ 9 | /* 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions 12 | are met: 13 | 14 | - Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | 17 | - Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 25 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #ifndef MATHOPS_H 35 | #define MATHOPS_H 36 | 37 | #include "arch.h" 38 | #include "entcode.h" 39 | #include "os_support.h" 40 | 41 | #define PI 3.141592653f 42 | 43 | /* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ 44 | #define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15) 45 | 46 | unsigned isqrt32(opus_uint32 _val); 47 | 48 | /* CELT doesn't need it for fixed-point, by analysis.c does. */ 49 | #if !defined(FIXED_POINT) || defined(ANALYSIS_C) 50 | #define cA 0.43157974f 51 | #define cB 0.67848403f 52 | #define cC 0.08595542f 53 | #define cE ((float)PI/2) 54 | static OPUS_INLINE float fast_atan2f(float y, float x) { 55 | float x2, y2; 56 | x2 = x*x; 57 | y2 = y*y; 58 | /* For very small values, we don't care about the answer, so 59 | we can just return 0. */ 60 | if (x2 + y2 < 1e-18f) 61 | { 62 | return 0; 63 | } 64 | if(x2>23)-127; 140 | in.i -= integer<<23; 141 | frac = in.f - 1.5f; 142 | frac = -0.41445418f + frac*(0.95909232f 143 | + frac*(-0.33951290f + frac*0.16541097f)); 144 | return 1+integer+frac; 145 | } 146 | 147 | /** Base-2 exponential approximation (2^x). */ 148 | static OPUS_INLINE float celt_exp2(float x) 149 | { 150 | int integer; 151 | float frac; 152 | union { 153 | float f; 154 | opus_uint32 i; 155 | } res; 156 | integer = floor(x); 157 | if (integer < -50) 158 | return 0; 159 | frac = x-integer; 160 | /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ 161 | res.f = 0.99992522f + frac * (0.69583354f 162 | + frac * (0.22606716f + 0.078024523f*frac)); 163 | res.i = (res.i + (integer<<23)) & 0x7fffffff; 164 | return res.f; 165 | } 166 | 167 | #else 168 | #define celt_log2(x) ((float)(1.442695040888963387*log(x))) 169 | #define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) 170 | #endif 171 | 172 | #endif 173 | 174 | #ifdef FIXED_POINT 175 | 176 | #include "os_support.h" 177 | 178 | #ifndef OVERRIDE_CELT_ILOG2 179 | /** Integer log in base2. Undefined for zero and negative numbers */ 180 | static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x) 181 | { 182 | celt_sig_assert(x>0); 183 | return EC_ILOG(x)-1; 184 | } 185 | #endif 186 | 187 | 188 | /** Integer log in base2. Defined for zero, but not for negative numbers */ 189 | static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x) 190 | { 191 | return x <= 0 ? 0 : celt_ilog2(x); 192 | } 193 | 194 | opus_val16 celt_rsqrt_norm(opus_val32 x); 195 | 196 | opus_val32 celt_sqrt(opus_val32 x); 197 | 198 | opus_val16 celt_cos_norm(opus_val32 x); 199 | 200 | /** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */ 201 | static OPUS_INLINE opus_val16 celt_log2(opus_val32 x) 202 | { 203 | int i; 204 | opus_val16 n, frac; 205 | /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605, 206 | 0.15530808010959576, -0.08556153059057618 */ 207 | static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401}; 208 | if (x==0) 209 | return -32767; 210 | i = celt_ilog2(x); 211 | n = VSHR32(x,i-15)-32768-16384; 212 | frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4])))))))); 213 | return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT); 214 | } 215 | 216 | /* 217 | K0 = 1 218 | K1 = log(2) 219 | K2 = 3-4*log(2) 220 | K3 = 3*log(2) - 2 221 | */ 222 | #define D0 16383 223 | #define D1 22804 224 | #define D2 14819 225 | #define D3 10204 226 | 227 | static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x) 228 | { 229 | opus_val16 frac; 230 | frac = SHL16(x, 4); 231 | return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); 232 | } 233 | /** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */ 234 | static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x) 235 | { 236 | int integer; 237 | opus_val16 frac; 238 | integer = SHR16(x,10); 239 | if (integer>14) 240 | return 0x7f000000; 241 | else if (integer < -15) 242 | return 0; 243 | frac = celt_exp2_frac(x-SHL16(integer,10)); 244 | return VSHR32(EXTEND32(frac), -integer-2); 245 | } 246 | 247 | opus_val32 celt_rcp(opus_val32 x); 248 | 249 | #define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b)) 250 | 251 | opus_val32 frac_div32(opus_val32 a, opus_val32 b); 252 | 253 | #define M1 32767 254 | #define M2 -21 255 | #define M3 -11943 256 | #define M4 4936 257 | 258 | /* Atan approximation using a 4th order polynomial. Input is in Q15 format 259 | and normalized by pi/4. Output is in Q15 format */ 260 | static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x) 261 | { 262 | return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); 263 | } 264 | 265 | #undef M1 266 | #undef M2 267 | #undef M3 268 | #undef M4 269 | 270 | /* atan2() approximation valid for positive input values */ 271 | static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x) 272 | { 273 | if (y < x) 274 | { 275 | opus_val32 arg; 276 | arg = celt_div(SHL32(EXTEND32(y),15),x); 277 | if (arg >= 32767) 278 | arg = 32767; 279 | return SHR16(celt_atan01(EXTRACT16(arg)),1); 280 | } else { 281 | opus_val32 arg; 282 | arg = celt_div(SHL32(EXTEND32(x),15),y); 283 | if (arg >= 32767) 284 | arg = 32767; 285 | return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); 286 | } 287 | } 288 | 289 | #endif /* FIXED_POINT */ 290 | #endif /* MATHOPS_H */ 291 | -------------------------------------------------------------------------------- /extension/include/celt/os_support.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007 Jean-Marc Valin 2 | 3 | File: os_support.h 4 | This is the (tiny) OS abstraction layer. Aside from math.h, this is the 5 | only place where system headers are allowed. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef OS_SUPPORT_H 32 | #define OS_SUPPORT_H 33 | 34 | #ifdef CUSTOM_SUPPORT 35 | # include "custom_support.h" 36 | #endif 37 | 38 | #include "opus_types.h" 39 | #include "opus_defines.h" 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | /** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ 46 | #ifndef OVERRIDE_OPUS_ALLOC 47 | static OPUS_INLINE void *opus_alloc (size_t size) 48 | { 49 | return malloc(size); 50 | } 51 | #endif 52 | 53 | /** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ 54 | #ifndef OVERRIDE_OPUS_ALLOC_SCRATCH 55 | static OPUS_INLINE void *opus_alloc_scratch (size_t size) 56 | { 57 | /* Scratch space doesn't need to be cleared */ 58 | return opus_alloc(size); 59 | } 60 | #endif 61 | 62 | /** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */ 63 | #ifndef OVERRIDE_OPUS_FREE 64 | static OPUS_INLINE void opus_free (void *ptr) 65 | { 66 | free(ptr); 67 | } 68 | #endif 69 | 70 | /** Copy n elements from src to dst. The 0* term provides compile-time type checking */ 71 | #ifndef OVERRIDE_OPUS_COPY 72 | #define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) 73 | #endif 74 | 75 | /** Copy n elements from src to dst, allowing overlapping regions. The 0* term 76 | provides compile-time type checking */ 77 | #ifndef OVERRIDE_OPUS_MOVE 78 | #define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) 79 | #endif 80 | 81 | /** Set n elements of dst to zero */ 82 | #ifndef OVERRIDE_OPUS_CLEAR 83 | #define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst)))) 84 | #endif 85 | 86 | /*#ifdef __GNUC__ 87 | #pragma GCC poison printf sprintf 88 | #pragma GCC poison malloc free realloc calloc 89 | #endif*/ 90 | 91 | #endif /* OS_SUPPORT_H */ 92 | 93 | -------------------------------------------------------------------------------- /extension/include/opus-dev.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SouthernCrossGaming/voicemanager/789fa2ee045f2ed4f61412d60dd91d58c6c086b4/extension/include/opus-dev.lib -------------------------------------------------------------------------------- /extension/include/opus.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SouthernCrossGaming/voicemanager/789fa2ee045f2ed4f61412d60dd91d58c6c086b4/extension/include/opus.dll -------------------------------------------------------------------------------- /extension/include/opus.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SouthernCrossGaming/voicemanager/789fa2ee045f2ed4f61412d60dd91d58c6c086b4/extension/include/opus.lib -------------------------------------------------------------------------------- /extension/include/opus1.3.1.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SouthernCrossGaming/voicemanager/789fa2ee045f2ed4f61412d60dd91d58c6c086b4/extension/include/opus1.3.1.lib -------------------------------------------------------------------------------- /extension/include/opus_custom.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2008 CSIRO 2 | Copyright (c) 2007-2009 Xiph.Org Foundation 3 | Copyright (c) 2008-2012 Gregory Maxwell 4 | Written by Jean-Marc Valin and Gregory Maxwell */ 5 | /* 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | - Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | - Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 21 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /** 31 | @file opus_custom.h 32 | @brief Opus-Custom reference implementation API 33 | */ 34 | 35 | #ifndef OPUS_CUSTOM_H 36 | #define OPUS_CUSTOM_H 37 | 38 | #include "opus_defines.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | #ifdef CUSTOM_MODES 45 | # define OPUS_CUSTOM_EXPORT OPUS_EXPORT 46 | # define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT 47 | #else 48 | # define OPUS_CUSTOM_EXPORT 49 | # ifdef OPUS_BUILD 50 | # define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE 51 | # else 52 | # define OPUS_CUSTOM_EXPORT_STATIC 53 | # endif 54 | #endif 55 | 56 | /** @defgroup opus_custom Opus Custom 57 | * @{ 58 | * Opus Custom is an optional part of the Opus specification and 59 | * reference implementation which uses a distinct API from the regular 60 | * API and supports frame sizes that are not normally supported.\ Use 61 | * of Opus Custom is discouraged for all but very special applications 62 | * for which a frame size different from 2.5, 5, 10, or 20 ms is needed 63 | * (for either complexity or latency reasons) and where interoperability 64 | * is less important. 65 | * 66 | * In addition to the interoperability limitations the use of Opus custom 67 | * disables a substantial chunk of the codec and generally lowers the 68 | * quality available at a given bitrate. Normally when an application needs 69 | * a different frame size from the codec it should buffer to match the 70 | * sizes but this adds a small amount of delay which may be important 71 | * in some very low latency applications. Some transports (especially 72 | * constant rate RF transports) may also work best with frames of 73 | * particular durations. 74 | * 75 | * Libopus only supports custom modes if they are enabled at compile time. 76 | * 77 | * The Opus Custom API is similar to the regular API but the 78 | * @ref opus_encoder_create and @ref opus_decoder_create calls take 79 | * an additional mode parameter which is a structure produced by 80 | * a call to @ref opus_custom_mode_create. Both the encoder and decoder 81 | * must create a mode using the same sample rate (fs) and frame size 82 | * (frame size) so these parameters must either be signaled out of band 83 | * or fixed in a particular implementation. 84 | * 85 | * Similar to regular Opus the custom modes support on the fly frame size 86 | * switching, but the sizes available depend on the particular frame size in 87 | * use. For some initial frame sizes on a single on the fly size is available. 88 | */ 89 | 90 | /** Contains the state of an encoder. One encoder state is needed 91 | for each stream. It is initialized once at the beginning of the 92 | stream. Do *not* re-initialize the state for every frame. 93 | @brief Encoder state 94 | */ 95 | typedef struct OpusCustomEncoder OpusCustomEncoder; 96 | 97 | /** State of the decoder. One decoder state is needed for each stream. 98 | It is initialized once at the beginning of the stream. Do *not* 99 | re-initialize the state for every frame. 100 | @brief Decoder state 101 | */ 102 | typedef struct OpusCustomDecoder OpusCustomDecoder; 103 | 104 | /** The mode contains all the information necessary to create an 105 | encoder. Both the encoder and decoder need to be initialized 106 | with exactly the same mode, otherwise the output will be 107 | corrupted. 108 | @brief Mode configuration 109 | */ 110 | typedef struct OpusCustomMode OpusCustomMode; 111 | 112 | /** Creates a new mode struct. This will be passed to an encoder or 113 | * decoder. The mode MUST NOT BE DESTROYED until the encoders and 114 | * decoders that use it are destroyed as well. 115 | * @param [in] Fs int: Sampling rate (8000 to 96000 Hz) 116 | * @param [in] frame_size int: Number of samples (per channel) to encode in each 117 | * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes) 118 | * @param [out] error int*: Returned error code (if NULL, no error will be returned) 119 | * @return A newly created mode 120 | */ 121 | OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error); 122 | 123 | /** Destroys a mode struct. Only call this after all encoders and 124 | * decoders using this mode are destroyed as well. 125 | * @param [in] mode OpusCustomMode*: Mode to be freed. 126 | */ 127 | OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode); 128 | 129 | 130 | #if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C) 131 | 132 | /* Encoder */ 133 | /** Gets the size of an OpusCustomEncoder structure. 134 | * @param [in] mode OpusCustomMode *: Mode configuration 135 | * @param [in] channels int: Number of channels 136 | * @returns size 137 | */ 138 | OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size( 139 | const OpusCustomMode *mode, 140 | int channels 141 | ) OPUS_ARG_NONNULL(1); 142 | 143 | # ifdef CUSTOM_MODES 144 | /** Initializes a previously allocated encoder state 145 | * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size. 146 | * This is intended for applications which use their own allocator instead of malloc. 147 | * @see opus_custom_encoder_create(),opus_custom_encoder_get_size() 148 | * To reset a previously initialized state use the OPUS_RESET_STATE CTL. 149 | * @param [in] st OpusCustomEncoder*: Encoder state 150 | * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of 151 | * the stream (must be the same characteristics as used for the 152 | * decoder) 153 | * @param [in] channels int: Number of channels 154 | * @return OPUS_OK Success or @ref opus_errorcodes 155 | */ 156 | OPUS_CUSTOM_EXPORT int opus_custom_encoder_init( 157 | OpusCustomEncoder *st, 158 | const OpusCustomMode *mode, 159 | int channels 160 | ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); 161 | # endif 162 | #endif 163 | 164 | 165 | /** Creates a new encoder state. Each stream needs its own encoder 166 | * state (can't be shared across simultaneous streams). 167 | * @param [in] mode OpusCustomMode*: Contains all the information about the characteristics of 168 | * the stream (must be the same characteristics as used for the 169 | * decoder) 170 | * @param [in] channels int: Number of channels 171 | * @param [out] error int*: Returns an error code 172 | * @return Newly created encoder state. 173 | */ 174 | OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create( 175 | const OpusCustomMode *mode, 176 | int channels, 177 | int *error 178 | ) OPUS_ARG_NONNULL(1); 179 | 180 | 181 | /** Destroys a an encoder state. 182 | * @param[in] st OpusCustomEncoder*: State to be freed. 183 | */ 184 | OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); 185 | 186 | /** Encodes a frame of audio. 187 | * @param [in] st OpusCustomEncoder*: Encoder state 188 | * @param [in] pcm float*: PCM audio in float format, with a normal range of +/-1.0. 189 | * Samples with a range beyond +/-1.0 are supported but will 190 | * be clipped by decoders using the integer API and should 191 | * only be used if it is known that the far end supports 192 | * extended dynamic range. There must be exactly 193 | * frame_size samples per channel. 194 | * @param [in] frame_size int: Number of samples per frame of input signal 195 | * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. 196 | * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame 197 | * (can change from one frame to another) 198 | * @return Number of bytes written to "compressed". 199 | * If negative, an error has occurred (see error codes). It is IMPORTANT that 200 | * the length returned be somehow transmitted to the decoder. Otherwise, no 201 | * decoding is possible. 202 | */ 203 | OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float( 204 | OpusCustomEncoder *st, 205 | const float *pcm, 206 | int frame_size, 207 | unsigned char *compressed, 208 | int maxCompressedBytes 209 | ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); 210 | 211 | /** Encodes a frame of audio. 212 | * @param [in] st OpusCustomEncoder*: Encoder state 213 | * @param [in] pcm opus_int16*: PCM audio in signed 16-bit format (native endian). 214 | * There must be exactly frame_size samples per channel. 215 | * @param [in] frame_size int: Number of samples per frame of input signal 216 | * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. 217 | * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame 218 | * (can change from one frame to another) 219 | * @return Number of bytes written to "compressed". 220 | * If negative, an error has occurred (see error codes). It is IMPORTANT that 221 | * the length returned be somehow transmitted to the decoder. Otherwise, no 222 | * decoding is possible. 223 | */ 224 | OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode( 225 | OpusCustomEncoder *st, 226 | const opus_int16 *pcm, 227 | int frame_size, 228 | unsigned char *compressed, 229 | int maxCompressedBytes 230 | ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); 231 | 232 | /** Perform a CTL function on an Opus custom encoder. 233 | * 234 | * Generally the request and subsequent arguments are generated 235 | * by a convenience macro. 236 | * @see opus_encoderctls 237 | */ 238 | OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); 239 | 240 | 241 | #if !defined(OPUS_BUILD) || defined(CELT_DECODER_C) 242 | /* Decoder */ 243 | 244 | /** Gets the size of an OpusCustomDecoder structure. 245 | * @param [in] mode OpusCustomMode *: Mode configuration 246 | * @param [in] channels int: Number of channels 247 | * @returns size 248 | */ 249 | OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size( 250 | const OpusCustomMode *mode, 251 | int channels 252 | ) OPUS_ARG_NONNULL(1); 253 | 254 | /** Initializes a previously allocated decoder state 255 | * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size. 256 | * This is intended for applications which use their own allocator instead of malloc. 257 | * @see opus_custom_decoder_create(),opus_custom_decoder_get_size() 258 | * To reset a previously initialized state use the OPUS_RESET_STATE CTL. 259 | * @param [in] st OpusCustomDecoder*: Decoder state 260 | * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of 261 | * the stream (must be the same characteristics as used for the 262 | * encoder) 263 | * @param [in] channels int: Number of channels 264 | * @return OPUS_OK Success or @ref opus_errorcodes 265 | */ 266 | OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init( 267 | OpusCustomDecoder *st, 268 | const OpusCustomMode *mode, 269 | int channels 270 | ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); 271 | 272 | #endif 273 | 274 | 275 | /** Creates a new decoder state. Each stream needs its own decoder state (can't 276 | * be shared across simultaneous streams). 277 | * @param [in] mode OpusCustomMode: Contains all the information about the characteristics of the 278 | * stream (must be the same characteristics as used for the encoder) 279 | * @param [in] channels int: Number of channels 280 | * @param [out] error int*: Returns an error code 281 | * @return Newly created decoder state. 282 | */ 283 | OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create( 284 | const OpusCustomMode *mode, 285 | int channels, 286 | int *error 287 | ) OPUS_ARG_NONNULL(1); 288 | 289 | /** Destroys a an decoder state. 290 | * @param[in] st OpusCustomDecoder*: State to be freed. 291 | */ 292 | OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); 293 | 294 | /** Decode an opus custom frame with floating point output 295 | * @param [in] st OpusCustomDecoder*: Decoder state 296 | * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss 297 | * @param [in] len int: Number of bytes in payload 298 | * @param [out] pcm float*: Output signal (interleaved if 2 channels). length 299 | * is frame_size*channels*sizeof(float) 300 | * @param [in] frame_size Number of samples per channel of available space in *pcm. 301 | * @returns Number of decoded samples or @ref opus_errorcodes 302 | */ 303 | OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float( 304 | OpusCustomDecoder *st, 305 | const unsigned char *data, 306 | int len, 307 | float *pcm, 308 | int frame_size 309 | ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); 310 | 311 | /** Decode an opus custom frame 312 | * @param [in] st OpusCustomDecoder*: Decoder state 313 | * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss 314 | * @param [in] len int: Number of bytes in payload 315 | * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length 316 | * is frame_size*channels*sizeof(opus_int16) 317 | * @param [in] frame_size Number of samples per channel of available space in *pcm. 318 | * @returns Number of decoded samples or @ref opus_errorcodes 319 | */ 320 | OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode( 321 | OpusCustomDecoder *st, 322 | const unsigned char *data, 323 | int len, 324 | opus_int16 *pcm, 325 | int frame_size 326 | ) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); 327 | 328 | /** Perform a CTL function on an Opus custom decoder. 329 | * 330 | * Generally the request and subsequent arguments are generated 331 | * by a convenience macro. 332 | * @see opus_genericctls 333 | */ 334 | OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); 335 | 336 | /**@}*/ 337 | 338 | #ifdef __cplusplus 339 | } 340 | #endif 341 | 342 | #endif /* OPUS_CUSTOM_H */ 343 | -------------------------------------------------------------------------------- /extension/include/opus_types.h: -------------------------------------------------------------------------------- 1 | /* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ 2 | /* Modified by Jean-Marc Valin */ 3 | /* 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | /* opus_types.h based on ogg_types.h from libogg */ 28 | 29 | /** 30 | @file opus_types.h 31 | @brief Opus reference implementation types 32 | */ 33 | #ifndef OPUS_TYPES_H 34 | #define OPUS_TYPES_H 35 | 36 | #define opus_int int /* used for counters etc; at least 16 bits */ 37 | #define opus_int64 long long 38 | #define opus_int8 signed char 39 | 40 | #define opus_uint unsigned int /* used for counters etc; at least 16 bits */ 41 | #define opus_uint64 unsigned long long 42 | #define opus_uint8 unsigned char 43 | 44 | /* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ 45 | #if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) 46 | #include 47 | # undef opus_int64 48 | # undef opus_int8 49 | # undef opus_uint64 50 | # undef opus_uint8 51 | typedef int8_t opus_int8; 52 | typedef uint8_t opus_uint8; 53 | typedef int16_t opus_int16; 54 | typedef uint16_t opus_uint16; 55 | typedef int32_t opus_int32; 56 | typedef uint32_t opus_uint32; 57 | typedef int64_t opus_int64; 58 | typedef uint64_t opus_uint64; 59 | #elif defined(_WIN32) 60 | 61 | # if defined(__CYGWIN__) 62 | # include <_G_config.h> 63 | typedef _G_int32_t opus_int32; 64 | typedef _G_uint32_t opus_uint32; 65 | typedef _G_int16 opus_int16; 66 | typedef _G_uint16 opus_uint16; 67 | # elif defined(__MINGW32__) 68 | typedef short opus_int16; 69 | typedef unsigned short opus_uint16; 70 | typedef int opus_int32; 71 | typedef unsigned int opus_uint32; 72 | # elif defined(__MWERKS__) 73 | typedef int opus_int32; 74 | typedef unsigned int opus_uint32; 75 | typedef short opus_int16; 76 | typedef unsigned short opus_uint16; 77 | # else 78 | /* MSVC/Borland */ 79 | typedef __int32 opus_int32; 80 | typedef unsigned __int32 opus_uint32; 81 | typedef __int16 opus_int16; 82 | typedef unsigned __int16 opus_uint16; 83 | # endif 84 | 85 | #elif defined(__MACOS__) 86 | 87 | # include 88 | typedef SInt16 opus_int16; 89 | typedef UInt16 opus_uint16; 90 | typedef SInt32 opus_int32; 91 | typedef UInt32 opus_uint32; 92 | 93 | #elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ 94 | 95 | # include 96 | typedef int16_t opus_int16; 97 | typedef u_int16_t opus_uint16; 98 | typedef int32_t opus_int32; 99 | typedef u_int32_t opus_uint32; 100 | 101 | #elif defined(__BEOS__) 102 | 103 | /* Be */ 104 | # include 105 | typedef int16 opus_int16; 106 | typedef u_int16 opus_uint16; 107 | typedef int32_t opus_int32; 108 | typedef u_int32_t opus_uint32; 109 | 110 | #elif defined (__EMX__) 111 | 112 | /* OS/2 GCC */ 113 | typedef short opus_int16; 114 | typedef unsigned short opus_uint16; 115 | typedef int opus_int32; 116 | typedef unsigned int opus_uint32; 117 | 118 | #elif defined (DJGPP) 119 | 120 | /* DJGPP */ 121 | typedef short opus_int16; 122 | typedef unsigned short opus_uint16; 123 | typedef int opus_int32; 124 | typedef unsigned int opus_uint32; 125 | 126 | #elif defined(R5900) 127 | 128 | /* PS2 EE */ 129 | typedef int opus_int32; 130 | typedef unsigned opus_uint32; 131 | typedef short opus_int16; 132 | typedef unsigned short opus_uint16; 133 | 134 | #elif defined(__SYMBIAN32__) 135 | 136 | /* Symbian GCC */ 137 | typedef signed short opus_int16; 138 | typedef unsigned short opus_uint16; 139 | typedef signed int opus_int32; 140 | typedef unsigned int opus_uint32; 141 | 142 | #elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) 143 | 144 | typedef short opus_int16; 145 | typedef unsigned short opus_uint16; 146 | typedef long opus_int32; 147 | typedef unsigned long opus_uint32; 148 | 149 | #elif defined(CONFIG_TI_C6X) 150 | 151 | typedef short opus_int16; 152 | typedef unsigned short opus_uint16; 153 | typedef int opus_int32; 154 | typedef unsigned int opus_uint32; 155 | 156 | #else 157 | 158 | /* Give up, take a reasonable guess */ 159 | typedef short opus_int16; 160 | typedef unsigned short opus_uint16; 161 | typedef int opus_int32; 162 | typedef unsigned int opus_uint32; 163 | 164 | #endif 165 | 166 | #endif /* OPUS_TYPES_H */ 167 | -------------------------------------------------------------------------------- /extension/inetmessage.h: -------------------------------------------------------------------------------- 1 | //========= Copyright Valve Corporation, All rights reserved. ============// 2 | // 3 | // Purpose: INetMessage interface 4 | // 5 | // $NoKeywords: $ 6 | //=============================================================================// 7 | 8 | #ifndef INETMESSAGE_FRAEVEN_H 9 | #define INETMESSAGE_FRAEVEN_H 10 | 11 | #include "smsdk_ext.h" 12 | #include "bitbuf.h" 13 | #include "inetchannelinfo.h" 14 | 15 | class INetMsgHandler; 16 | class INetMessage; 17 | class INetChannel; 18 | 19 | // typedef bool (INetMsgHandler::*PROCESSFUNCPTR)(INetMessage*); 20 | // #define CASTPROCPTR( fn ) static_cast (fn) 21 | 22 | class INetMessage 23 | { 24 | public: 25 | virtual ~INetMessage() {}; 26 | 27 | // Use these to setup who can hear whose voice. 28 | // Pass in client indices (which are their ent indices - 1). 29 | 30 | virtual void SetNetChannel(INetChannel * netchan) = 0; // netchannel this message is from/for 31 | virtual void SetReliable( bool state ) = 0; // set to true if it's a reliable message 32 | 33 | virtual bool Process( void ) = 0; // calles the recently set handler to process this message 34 | 35 | virtual bool ReadFromBuffer( bf_read &buffer ) = 0; // returns true if parsing was OK 36 | virtual bool WriteToBuffer( bf_write &buffer ) = 0; // returns true if writing was OK 37 | 38 | virtual bool IsReliable( void ) const = 0; // true, if message needs reliable handling 39 | 40 | virtual int GetType( void ) const = 0; // returns module specific header tag eg svc_serverinfo 41 | virtual int GetGroup( void ) const = 0; // returns net message group of this message 42 | virtual const char *GetName( void ) const = 0; // returns network message name, eg "svc_serverinfo" 43 | virtual INetChannel *GetNetChannel( void ) const = 0; 44 | virtual const char *ToString( void ) const = 0; // returns a human readable string about message content 45 | }; 46 | 47 | class CNetMessage : public INetMessage 48 | { 49 | public: 50 | CNetMessage() { m_bReliable = true; 51 | m_NetChannel = NULL; } 52 | 53 | virtual ~CNetMessage() {}; 54 | 55 | virtual int GetGroup() const { return INetChannelInfo::GENERIC; } 56 | INetChannel *GetNetChannel() const { return m_NetChannel; } 57 | 58 | virtual void SetReliable( bool state) {m_bReliable = state;}; 59 | virtual bool IsReliable() const { return m_bReliable; }; 60 | virtual void SetNetChannel(INetChannel * netchan) { m_NetChannel = netchan; } 61 | virtual bool Process() { return false; }; // no handler set 62 | 63 | protected: 64 | bool m_bReliable; // true if message should be send reliable 65 | INetChannel *m_NetChannel; // netchannel this message is from/for 66 | }; 67 | 68 | #define svc_VoiceData 15 69 | 70 | #define DECLARE_BASE_MESSAGE( msgtype ) \ 71 | public: \ 72 | bool ReadFromBuffer( bf_read &buffer ); \ 73 | bool WriteToBuffer( bf_write &buffer ); \ 74 | const char *ToString() const; \ 75 | int GetType() const { return msgtype; } \ 76 | const char *GetName() const { return #msgtype;}\ 77 | 78 | #define DECLARE_SVC_MESSAGE( name ) \ 79 | DECLARE_BASE_MESSAGE( svc_##name ); \ 80 | IServerMessageHandler *m_pMessageHandler;\ 81 | bool Process() { return m_pMessageHandler->Process##name( this ); }\ 82 | 83 | class SVC_VoiceData : public CNetMessage 84 | { 85 | DECLARE_SVC_MESSAGE( VoiceData ); 86 | 87 | int GetGroup() const { return INetChannelInfo::VOICE; } 88 | 89 | SVC_VoiceData() { m_bReliable = false; } 90 | 91 | public: 92 | int m_nFromClient; // client who has spoken 93 | bool m_bProximity; 94 | int m_nLength; // data length in bits 95 | uint64 m_xuid; // X360 player ID 96 | 97 | bf_read m_DataIn; 98 | void *m_DataOut; 99 | }; 100 | 101 | #define NETMSG_TYPE_BITS 6 102 | 103 | bool SVC_VoiceData::WriteToBuffer( bf_write &buffer ) 104 | { 105 | buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); 106 | buffer.WriteByte( m_nFromClient ); 107 | buffer.WriteByte( m_bProximity ); 108 | buffer.WriteWord( m_nLength ); 109 | 110 | return buffer.WriteBits( m_DataOut, m_nLength ); 111 | } 112 | 113 | bool SVC_VoiceData::ReadFromBuffer( bf_read &buffer ) 114 | { 115 | // VPROF( "SVC_VoiceData::ReadFromBuffer" ); 116 | 117 | m_nFromClient = buffer.ReadByte(); 118 | m_bProximity = !!buffer.ReadByte(); 119 | m_nLength = buffer.ReadWord(); 120 | 121 | // if ( IsX360() ) 122 | // { 123 | // m_xuid = buffer.ReadLongLong(); 124 | // } 125 | 126 | m_DataIn = buffer; 127 | return buffer.SeekRelative( m_nLength ); 128 | } 129 | 130 | const char *SVC_VoiceData::ToString(void) const 131 | { 132 | // Q_snprintf(s_text, sizeof(s_text), "%s: client %i, bytes %i", GetName(), m_nFromClient, Bits2Bytes(m_nLength) ); 133 | // return s_text; 134 | return "idc"; 135 | } 136 | 137 | #endif 138 | 139 | -------------------------------------------------------------------------------- /extension/libc_compat.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" 4 | { 5 | __attribute__((__visibility__("default"), __cdecl__)) double __pow_finite(double a, double b) 6 | { 7 | return pow(a, b); 8 | } 9 | } -------------------------------------------------------------------------------- /extension/scripts/build.bat: -------------------------------------------------------------------------------- 1 | mkdir build 2 | cd build 3 | python ..\configure.py -s tf2,sdk2013 --sm-path C:\sourcemod --mms-path C:\metamod-source --hl2sdk-root C:\sdks --enable-optimize 4 | ambuild -------------------------------------------------------------------------------- /extension/scripts/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | mkdir build 4 | cd build 5 | python3 ../configure.py -s tf2,sdk2013 --sm-path /sourcemod --mms-path /metamod-source --hl2sdk-root /sdks --enable-optimize 6 | ambuild -------------------------------------------------------------------------------- /extension/scripts/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # vim: set ts=2 sw=2 tw=99 et: 3 | 4 | import sys 5 | 6 | def detect_distutils(): 7 | sys.path.pop(0) 8 | try: 9 | import ambuild2.util 10 | try: 11 | val = getattr(ambuild2.util, 'INSTALLED_BY_PIP_OR_SETUPTOOLS') 12 | except AttributeError: 13 | sys.exit(1) 14 | except ImportError: 15 | pass 16 | 17 | sys.exit(0) 18 | 19 | # This if statement is supposedly required by multiprocessing. 20 | if __name__ == '__main__': 21 | from setuptools import setup, find_packages 22 | try: 23 | import sqlite3 24 | except: 25 | raise SystemError('py-sqlite3 must be installed') 26 | 27 | amb_scripts = [] 28 | if sys.platform != 'win32': 29 | if sys.platform == 'darwin': 30 | amb_scripts.append('scripts/ambuild_dsymutil_wrapper.sh') 31 | else: 32 | amb_scripts.append('scripts/ambuild_objcopy_wrapper.sh') 33 | 34 | setup(name = 'AMBuild', 35 | version = '2.0', 36 | description = 'AlliedModders Build System', 37 | author = 'David Anderson', 38 | author_email = 'dvander@alliedmods.net', 39 | url = 'http://www.alliedmods.net/ambuild', 40 | packages = find_packages(), 41 | python_requires = '>=3.3', 42 | entry_points = {'console_scripts': ['ambuild = ambuild2.run:cli_run']}, 43 | scripts = amb_scripts, 44 | zip_safe = False) 45 | -------------------------------------------------------------------------------- /extension/smsdk_config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 : 3 | * ============================================================================= 4 | * SourceMod Sample Extension 5 | * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. 6 | * ============================================================================= 7 | * 8 | * This program is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU General Public License, version 3.0, as published by the 10 | * Free Software Foundation. 11 | * 12 | * This program is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License along with 18 | * this program. If not, see . 19 | * 20 | * As a special exception, AlliedModders LLC gives you permission to link the 21 | * code of this program (as well as its derivative works) to "Half-Life 2," the 22 | * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software 23 | * by the Valve Corporation. You must obey the GNU General Public License in 24 | * all respects for all other code used. Additionally, AlliedModders LLC grants 25 | * this exception to all derivative works. AlliedModders LLC defines further 26 | * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), 27 | * or . 28 | * 29 | * Version: $Id$ 30 | */ 31 | 32 | #ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ 33 | #define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ 34 | 35 | /** 36 | * @file smsdk_config.h 37 | * @brief Contains macros for configuring basic extension information. 38 | */ 39 | 40 | /* Basic information exposed publicly */ 41 | #define SMEXT_CONF_NAME "Voice Manager" 42 | #define SMEXT_CONF_DESCRIPTION "Do things to voice chat" 43 | #define SMEXT_CONF_VERSION "0.0.0.1" 44 | #define SMEXT_CONF_AUTHOR "Fraeven" 45 | #define SMEXT_CONF_URL "https://scg.wtf/" 46 | #define SMEXT_CONF_LOGTAG "VOICEMANAGER" 47 | #define SMEXT_CONF_LICENSE "GPL" 48 | #define SMEXT_CONF_DATESTRING __DATE__ 49 | 50 | /** 51 | * @brief Exposes plugin's main interface. 52 | */ 53 | #define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name; 54 | 55 | /** 56 | * @brief Sets whether or not this plugin required Metamod. 57 | * NOTE: Uncomment to enable, comment to disable. 58 | */ 59 | #define SMEXT_CONF_METAMOD 60 | 61 | /** Enable interfaces you want to use here by uncommenting lines */ 62 | #define SMEXT_ENABLE_FORWARDSYS 63 | #define SMEXT_ENABLE_HANDLESYS 64 | #define SMEXT_ENABLE_PLAYERHELPERS 65 | //#define SMEXT_ENABLE_DBMANAGER 66 | #define SMEXT_ENABLE_GAMECONF 67 | #define SMEXT_ENABLE_MEMUTILS 68 | #define SMEXT_ENABLE_GAMEHELPERS 69 | //#define SMEXT_ENABLE_TIMERSYS 70 | //#define SMEXT_ENABLE_THREADER 71 | //#define SMEXT_ENABLE_LIBSYS 72 | //#define SMEXT_ENABLE_MENUS 73 | //#define SMEXT_ENABLE_ADTFACTORY 74 | #define SMEXT_ENABLE_PLUGINSYS 75 | //#define SMEXT_ENABLE_ADMINSYS 76 | //#define SMEXT_ENABLE_TEXTPARSERS 77 | //#define SMEXT_ENABLE_USERMSGS 78 | //#define SMEXT_ENABLE_TRANSLATOR 79 | #define SMEXT_ENABLE_ROOTCONSOLEMENU 80 | 81 | #endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_ 82 | -------------------------------------------------------------------------------- /extension/smsdk_ext.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 sw=4 tw=99 noet: 3 | * ============================================================================= 4 | * SourceMod Base Extension Code 5 | * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. 6 | * ============================================================================= 7 | * 8 | * This program is free software; you can redistribute it and/or modify it under 9 | * the terms of the GNU General Public License, version 3.0, as published by the 10 | * Free Software Foundation. 11 | * 12 | * This program is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License along with 18 | * this program. If not, see . 19 | * 20 | * As a special exception, AlliedModders LLC gives you permission to link the 21 | * code of this program (as well as its derivative works) to "Half-Life 2," the 22 | * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software 23 | * by the Valve Corporation. You must obey the GNU General Public License in 24 | * all respects for all other code used. Additionally, AlliedModders LLC grants 25 | * this exception to all derivative works. AlliedModders LLC defines further 26 | * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), 27 | * or . 28 | * 29 | * Version: $Id$ 30 | */ 31 | 32 | #ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ 33 | #define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ 34 | 35 | /** 36 | * @file smsdk_ext.h 37 | * @brief Contains wrappers for making Extensions easier to write. 38 | */ 39 | 40 | #include "smsdk_config.h" 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include "am-string.h" 47 | #if defined SMEXT_ENABLE_FORWARDSYS 48 | #include 49 | #endif //SMEXT_ENABLE_FORWARDSYS 50 | #if defined SMEXT_ENABLE_PLAYERHELPERS 51 | #include 52 | #endif //SMEXT_ENABLE_PlAYERHELPERS 53 | #if defined SMEXT_ENABLE_DBMANAGER 54 | #include 55 | #endif //SMEXT_ENABLE_DBMANAGER 56 | #if defined SMEXT_ENABLE_GAMECONF 57 | #include 58 | #endif 59 | #if defined SMEXT_ENABLE_MEMUTILS 60 | #include 61 | #endif 62 | #if defined SMEXT_ENABLE_GAMEHELPERS 63 | #include 64 | #endif 65 | #if defined SMEXT_ENABLE_TIMERSYS 66 | #include 67 | #endif 68 | #if defined SMEXT_ENABLE_ADTFACTORY 69 | #include 70 | #endif 71 | #if defined SMEXT_ENABLE_THREADER 72 | #include 73 | #endif 74 | #if defined SMEXT_ENABLE_LIBSYS 75 | #include 76 | #endif 77 | #if defined SMEXT_ENABLE_PLUGINSYS 78 | #include 79 | #endif 80 | #if defined SMEXT_ENABLE_MENUS 81 | #include 82 | #endif 83 | #if defined SMEXT_ENABLE_ADMINSYS 84 | #include 85 | #endif 86 | #if defined SMEXT_ENABLE_TEXTPARSERS 87 | #include 88 | #endif 89 | #if defined SMEXT_ENABLE_USERMSGS 90 | #include 91 | #endif 92 | #if defined SMEXT_ENABLE_TRANSLATOR 93 | #include 94 | #endif 95 | #if defined SMEXT_ENABLE_ROOTCONSOLEMENU 96 | #include 97 | #endif 98 | 99 | #if defined SMEXT_CONF_METAMOD 100 | #include 101 | #ifndef META_NO_HL2SDK 102 | #include 103 | #endif //META_NO_HL2SDK 104 | #endif 105 | 106 | #if !defined METAMOD_PLAPI_VERSION 107 | #include 108 | #endif 109 | 110 | using namespace SourceMod; 111 | using namespace SourcePawn; 112 | 113 | class SDKExtension: 114 | #if defined SMEXT_CONF_METAMOD 115 | public ISmmPlugin, 116 | #endif 117 | public IExtensionInterface 118 | { 119 | public: 120 | /** Constructor */ 121 | SDKExtension(); 122 | public: 123 | /** 124 | * @brief This is called after the initial loading sequence has been processed. 125 | * 126 | * @param error Error message buffer. 127 | * @param maxlength Size of error message buffer. 128 | * @param late Whether or not the module was loaded after map load. 129 | * @return True to succeed loading, false to fail. 130 | */ 131 | virtual bool SDK_OnLoad(char* error, size_t maxlength, bool late); 132 | 133 | /** 134 | * @brief This is called once the extension unloading process begins. 135 | */ 136 | virtual void SDK_OnUnload(); 137 | 138 | /** 139 | * @brief This is called once all known extensions have been loaded. 140 | */ 141 | virtual void SDK_OnAllLoaded(); 142 | 143 | /** 144 | * @brief Called when the pause state is changed. 145 | */ 146 | virtual void SDK_OnPauseChange(bool paused); 147 | 148 | /** 149 | * @brief Called after SDK_OnUnload, once all dependencies have been 150 | * removed, and the extension is about to be removed from memory. 151 | */ 152 | virtual void SDK_OnDependenciesDropped(); 153 | 154 | #if defined SMEXT_CONF_METAMOD 155 | /** 156 | * @brief Called when Metamod is attached, before the extension version is called. 157 | * 158 | * @param error Error buffer. 159 | * @param maxlength Maximum size of error buffer. 160 | * @param late Whether or not Metamod considers this a late load. 161 | * @return True to succeed, false to fail. 162 | */ 163 | virtual bool SDK_OnMetamodLoad(ISmmAPI* ismm, char* error, size_t maxlength, bool late); 164 | 165 | /** 166 | * @brief Called when Metamod is detaching, after the extension version is called. 167 | * NOTE: By default this is blocked unless sent from SourceMod. 168 | * 169 | * @param error Error buffer. 170 | * @param maxlength Maximum size of error buffer. 171 | * @return True to succeed, false to fail. 172 | */ 173 | virtual bool SDK_OnMetamodUnload(char* error, size_t maxlength); 174 | 175 | /** 176 | * @brief Called when Metamod's pause state is changing. 177 | * NOTE: By default this is blocked unless sent from SourceMod. 178 | * 179 | * @param paused Pause state being set. 180 | * @param error Error buffer. 181 | * @param maxlength Maximum size of error buffer. 182 | * @return True to succeed, false to fail. 183 | */ 184 | virtual bool SDK_OnMetamodPauseChange(bool paused, char* error, size_t maxlength); 185 | #endif 186 | 187 | public: //IExtensionInterface 188 | virtual bool OnExtensionLoad(IExtension* me, IShareSys* sys, char* error, size_t maxlength, bool late); 189 | virtual void OnExtensionUnload(); 190 | virtual void OnExtensionsAllLoaded(); 191 | 192 | /** Returns whether or not this is a Metamod-based extension */ 193 | virtual bool IsMetamodExtension(); 194 | 195 | /** 196 | * @brief Called when the pause state changes. 197 | * 198 | * @param state True if being paused, false if being unpaused. 199 | */ 200 | virtual void OnExtensionPauseChange(bool state); 201 | 202 | /** Returns name */ 203 | virtual const char* GetExtensionName(); 204 | /** Returns URL */ 205 | virtual const char* GetExtensionURL(); 206 | /** Returns log tag */ 207 | virtual const char* GetExtensionTag(); 208 | /** Returns author */ 209 | virtual const char* GetExtensionAuthor(); 210 | /** Returns version string */ 211 | virtual const char* GetExtensionVerString(); 212 | /** Returns description string */ 213 | virtual const char* GetExtensionDescription(); 214 | /** Returns date string */ 215 | virtual const char* GetExtensionDateString(); 216 | 217 | /** Called after OnExtensionUnload, once dependencies have been dropped. */ 218 | virtual void OnDependenciesDropped(); 219 | #if defined SMEXT_CONF_METAMOD 220 | public: //ISmmPlugin 221 | /** Called when the extension is attached to Metamod. */ 222 | virtual bool Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlength, bool late); 223 | /** Returns the author to MM */ 224 | virtual const char* GetAuthor(); 225 | /** Returns the name to MM */ 226 | virtual const char* GetName(); 227 | /** Returns the description to MM */ 228 | virtual const char* GetDescription(); 229 | /** Returns the URL to MM */ 230 | virtual const char* GetURL(); 231 | /** Returns the license to MM */ 232 | virtual const char* GetLicense(); 233 | /** Returns the version string to MM */ 234 | virtual const char* GetVersion(); 235 | /** Returns the date string to MM */ 236 | virtual const char* GetDate(); 237 | /** Returns the logtag to MM */ 238 | virtual const char* GetLogTag(); 239 | /** Called on unload */ 240 | virtual bool Unload(char* error, size_t maxlength); 241 | /** Called on pause */ 242 | virtual bool Pause(char* error, size_t maxlength); 243 | /** Called on unpause */ 244 | virtual bool Unpause(char* error, size_t maxlength); 245 | private: 246 | bool m_SourceMMLoaded; 247 | bool m_WeAreUnloaded; 248 | bool m_WeGotPauseChange; 249 | #endif 250 | }; 251 | 252 | extern SDKExtension* g_pExtensionIface; 253 | extern IExtension* myself; 254 | 255 | extern IShareSys* g_pShareSys; 256 | extern IShareSys* sharesys; /* Note: Newer name */ 257 | extern ISourceMod* g_pSM; 258 | extern ISourceMod* smutils; /* Note: Newer name */ 259 | 260 | /* Optional interfaces are below */ 261 | #if defined SMEXT_ENABLE_FORWARDSYS 262 | extern IForwardManager* g_pForwards; 263 | extern IForwardManager* forwards; /* Note: Newer name */ 264 | #endif //SMEXT_ENABLE_FORWARDSYS 265 | #if defined SMEXT_ENABLE_HANDLESYS 266 | extern IHandleSys* g_pHandleSys; 267 | extern IHandleSys* handlesys; /* Note: Newer name */ 268 | #endif //SMEXT_ENABLE_HANDLESYS 269 | #if defined SMEXT_ENABLE_PLAYERHELPERS 270 | extern IPlayerManager* playerhelpers; 271 | #endif //SMEXT_ENABLE_PLAYERHELPERS 272 | #if defined SMEXT_ENABLE_DBMANAGER 273 | extern IDBManager* dbi; 274 | #endif //SMEXT_ENABLE_DBMANAGER 275 | #if defined SMEXT_ENABLE_GAMECONF 276 | extern IGameConfigManager* gameconfs; 277 | #endif //SMEXT_ENABLE_DBMANAGER 278 | #if defined SMEXT_ENABLE_MEMUTILS 279 | extern IMemoryUtils* memutils; 280 | #endif 281 | #if defined SMEXT_ENABLE_GAMEHELPERS 282 | extern IGameHelpers* gamehelpers; 283 | #endif 284 | #if defined SMEXT_ENABLE_TIMERSYS 285 | extern ITimerSystem* timersys; 286 | #endif 287 | #if defined SMEXT_ENABLE_ADTFACTORY 288 | extern IADTFactory* adtfactory; 289 | #endif 290 | #if defined SMEXT_ENABLE_THREADER 291 | extern IThreader* threader; 292 | #endif 293 | #if defined SMEXT_ENABLE_LIBSYS 294 | extern ILibrarySys* libsys; 295 | #endif 296 | #if defined SMEXT_ENABLE_PLUGINSYS 297 | extern SourceMod::IPluginManager* plsys; 298 | #endif 299 | #if defined SMEXT_ENABLE_MENUS 300 | extern IMenuManager* menus; 301 | #endif 302 | #if defined SMEXT_ENABLE_ADMINSYS 303 | extern IAdminSystem* adminsys; 304 | #endif 305 | #if defined SMEXT_ENABLE_USERMSGS 306 | extern IUserMessages* usermsgs; 307 | #endif 308 | #if defined SMEXT_ENABLE_TRANSLATOR 309 | extern ITranslator* translator; 310 | #endif 311 | #if defined SMEXT_ENABLE_ROOTCONSOLEMENU 312 | extern IRootConsole* rootconsole; 313 | #endif 314 | 315 | #if defined SMEXT_CONF_METAMOD 316 | PLUGIN_GLOBALVARS(); 317 | #ifndef META_NO_HL2SDK 318 | extern IVEngineServer* engine; 319 | extern IServerGameDLL* gamedll; 320 | #endif //META_NO_HL2SDK 321 | #endif 322 | 323 | /** Creates a SourceMod interface macro pair */ 324 | #define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION 325 | /** Automates retrieving SourceMod interfaces */ 326 | #define SM_GET_IFACE(prefix, addr) \ 327 | if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \ 328 | { \ 329 | if (error != NULL && maxlength) \ 330 | { \ 331 | size_t len = ke::SafeSprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ 332 | if (len >= maxlength) \ 333 | { \ 334 | error[maxlength - 1] = '\0'; \ 335 | } \ 336 | } \ 337 | return false; \ 338 | } 339 | /** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */ 340 | #define SM_GET_LATE_IFACE(prefix, addr) \ 341 | g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr) 342 | /** Validates a SourceMod interface pointer */ 343 | #define SM_CHECK_IFACE(prefix, addr) \ 344 | if (!addr) \ 345 | { \ 346 | if (error != NULL && maxlength) \ 347 | { \ 348 | size_t len = ke::SafeSprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \ 349 | if (len >= maxlength) \ 350 | { \ 351 | error[maxlength - 1] = '\0'; \ 352 | } \ 353 | } \ 354 | return false; \ 355 | } 356 | 357 | #endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_ 358 | -------------------------------------------------------------------------------- /extension/voicemanager.cpp: -------------------------------------------------------------------------------- 1 | #include "voicemanager.h" 2 | 3 | VoiceManager::VoiceManager() 4 | { 5 | m_gain = 0; 6 | m_vecDecodedChunks = std::vector(); 7 | } 8 | 9 | VoiceManager::VoiceManager(opus_int32 gain) 10 | { 11 | m_gain = gain; 12 | m_vecDecodedChunks = std::vector(); 13 | } 14 | 15 | uint8_t* VoiceManager::OnBroadcastVoiceData(IClient* pClient, int nBytes, const uint8_t* data, int* nBytesOut) 16 | { 17 | *nBytesOut = 0; 18 | m_vecDecodedChunks.clear(); 19 | 20 | uint8_t* originalVoiceData = new uint8_t[MAX_PACKET_SIZE](); 21 | std::copy(data, data + nBytes, &originalVoiceData[0]); 22 | 23 | uint8_t* pVoiceDataResult = new uint8_t[MAX_PACKET_SIZE](); 24 | std::copy(data, data + nBytes, &pVoiceDataResult[0]); 25 | 26 | ParseSteamVoicePacket(pVoiceDataResult, nBytes); 27 | 28 | if (m_vecDecodedChunks.size() <= 0 || !InitOpusEncoder(m_sampleRate)) 29 | { 30 | delete[] pVoiceDataResult; 31 | return originalVoiceData; 32 | } 33 | 34 | int16_t encPos = STEAM_HEADER_SIZE + 2; 35 | 36 | for (DecodedChunk decoded : m_vecDecodedChunks) 37 | { 38 | EncodedChunk encoded = OpusEncode(decoded); 39 | if (encoded.data.size() <= 0) 40 | { 41 | delete[] pVoiceDataResult; 42 | return originalVoiceData; 43 | } 44 | 45 | auto encodedSize = encoded.data.size(); 46 | char* pEncodedSize = (char*)&encodedSize; 47 | std::copy(pEncodedSize, pEncodedSize + sizeof(int16_t), &pVoiceDataResult[encPos]); 48 | encPos += 2; 49 | 50 | char* pIndex = (char*)&encoded.index; 51 | std::copy(pIndex, pIndex + sizeof(int16_t), &pVoiceDataResult[encPos]); 52 | encPos += 2; 53 | 54 | std::copy(encoded.data.data(), encoded.data.data() + encoded.data.size(), &pVoiceDataResult[encPos]); 55 | 56 | encPos += encoded.data.size(); 57 | } 58 | 59 | int16_t voiceDataLength = encPos - STEAM_HEADER_SIZE - 2; 60 | if (voiceDataLength <= 0) 61 | { 62 | delete[] pVoiceDataResult; 63 | return originalVoiceData; 64 | } 65 | 66 | // Copy the voice data byte length to the output data, just after the header info 67 | char* pVoiceDataLength = (char*)&voiceDataLength; 68 | std::copy(pVoiceDataLength, pVoiceDataLength + sizeof(uint16_t), &pVoiceDataResult[STEAM_HEADER_SIZE]); 69 | 70 | uint32_t newCRC = CRC::Calculate(pVoiceDataResult, encPos, CRC::CRC_32()); 71 | 72 | // Copy the new CRC to the end of the output data 73 | char* pNewCRC = (char*)&newCRC; 74 | std::copy(pNewCRC, pNewCRC + sizeof(uint32_t), &pVoiceDataResult[encPos]); 75 | 76 | *nBytesOut = STEAM_HEADER_SIZE + 2 + voiceDataLength + sizeof(uint32_t); 77 | 78 | delete[] originalVoiceData; 79 | return pVoiceDataResult; 80 | } 81 | 82 | void VoiceManager::ParseSteamVoicePacket(uint8_t* bytes, int numBytes) 83 | { 84 | int numDecompressedSamples = 0; 85 | int pos = 0; 86 | if (numBytes < 4 + 4 + 4 + 1 + 2) 87 | { 88 | return; 89 | } 90 | 91 | int dataLen = numBytes - 4; // skip CRC 92 | 93 | uint32_t CRCdemo = *((uint32_t*)&bytes[dataLen]); 94 | uint32_t CRCdata = CRC::Calculate(bytes, dataLen, CRC::CRC_32()); 95 | if (CRCdata != CRCdemo) 96 | { 97 | return; 98 | } 99 | 100 | pos += 4; 101 | uint32_t iSteamCommunity = *((uint32_t*)&bytes[pos]); 102 | pos += 4; 103 | 104 | // What was this for, bot detection? 105 | if (iSteamCommunity != 0x1100001) 106 | { 107 | return; 108 | } 109 | 110 | while (pos < dataLen) 111 | { 112 | uint8_t payloadType = bytes[pos]; 113 | pos++; 114 | 115 | switch (payloadType) 116 | { 117 | case 11: // Sample Rate 118 | { 119 | if (pos + 2 > dataLen) 120 | { 121 | return; 122 | } 123 | 124 | int16_t rate = *((int16_t*)&bytes[pos]); 125 | pos += 2; 126 | m_sampleRate = (opus_int32)rate; 127 | if (!this->InitOpusDecoder(rate)) 128 | { 129 | return; 130 | } 131 | 132 | break; 133 | } 134 | case 6: // Opus 135 | { 136 | if (pos + 2 > dataLen) 137 | { 138 | return; 139 | } 140 | 141 | int16_t dataSize = *((int16_t*)&bytes[pos]); 142 | pos += 2; 143 | 144 | int actualDataSize = numBytes - STEAM_HEADER_SIZE - CRC_SIZE - sizeof(dataSize); 145 | if (actualDataSize != dataSize) 146 | { 147 | smutils->LogError(myself, "Specified size of voice data (%i bytes) does not match actual size (%i bytes).", dataSize, actualDataSize); 148 | return; 149 | } 150 | 151 | int tpos = pos; 152 | int maxpos = tpos + dataSize; 153 | while (tpos <= (maxpos - 4)) 154 | { 155 | EncodedChunk encodedChunk; 156 | int16_t encodedSize = *((int16_t*)&bytes[tpos]); 157 | encodedChunk.data = std::vector(encodedSize); 158 | tpos += 2; 159 | 160 | if (encodedSize <= 0) 161 | { 162 | smutils->LogError(myself, "Found a chunk with a size <= 0"); 163 | return; 164 | } 165 | 166 | encodedChunk.index = *((int16_t*)&bytes[tpos]); 167 | tpos += 2; 168 | 169 | for (int i = 0; i < encodedSize; i++) 170 | { 171 | encodedChunk.data[i] = bytes[tpos + i]; 172 | } 173 | 174 | DecodedChunk decodedChunk = this->OpusDecode(encodedChunk); 175 | if (decodedChunk.data.size() <= 0) 176 | { 177 | return; 178 | } 179 | 180 | m_vecDecodedChunks.push_back(decodedChunk); 181 | tpos += encodedChunk.data.size(); 182 | } 183 | } 184 | case 0: // Silence 185 | { 186 | return; 187 | } 188 | } 189 | } 190 | } 191 | 192 | bool VoiceManager::ConfigureEncoder() 193 | { 194 | int err = opus_encoder_ctl(m_Opus_Encoder, OPUS_SET_BITRATE(BITRATE)); 195 | if (err < 0) 196 | { 197 | smutils->LogError(myself, "Something went wrong with initing opus encoder ctl bitrate: %i", err); 198 | return false; 199 | } 200 | 201 | err = opus_encoder_ctl(m_Opus_Encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); 202 | if (err < 0) 203 | { 204 | smutils->LogError(myself, "Something went wrong with initing opus encoder ctl signal: %i", err); 205 | return false; 206 | } 207 | 208 | err = opus_encoder_ctl(m_Opus_Encoder, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); 209 | if (err < 0) 210 | { 211 | smutils->LogError(myself, "Something went wrong with initing opus encoder ctl bandwidth: %i", err); 212 | return false; 213 | } 214 | 215 | err = opus_encoder_ctl(m_Opus_Encoder, OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_20_MS)); 216 | if (err < 0) 217 | { 218 | smutils->LogError(myself, "Something went wrong with initing opus encoder ctl frame duration: %i", err); 219 | return false; 220 | } 221 | 222 | err = opus_encoder_ctl(m_Opus_Encoder, OPUS_SET_COMPLEXITY(10)); 223 | if (err < 0) 224 | { 225 | smutils->LogError(myself, "Something went wrong with initing opus encoder ctl frame complexity: %i", err); 226 | return false; 227 | } 228 | 229 | return true; 230 | } 231 | 232 | bool VoiceManager::InitOpusEncoder(opus_int32 rate) 233 | { 234 | if (!m_Opus_Encoder) 235 | { 236 | int err; 237 | m_Opus_Encoder = opus_encoder_create(rate, CHANNELS, APPLICATION, &err); 238 | err = opus_encoder_ctl(m_Opus_Encoder, OPUS_RESET_STATE); 239 | 240 | if (err < 0) 241 | { 242 | smutils->LogError(myself, "Something went wrong with initing opus encoder: %i", err); 243 | return false; 244 | } 245 | 246 | return ConfigureEncoder(); 247 | } 248 | 249 | // Already initialized 250 | return true; 251 | } 252 | 253 | bool VoiceManager::InitOpusDecoder(opus_int32 rate) 254 | { 255 | if (!m_Opus_Decoder) 256 | { 257 | int err; 258 | m_Opus_Decoder = opus_decoder_create(rate, CHANNELS, &err); 259 | 260 | if (err < 0) 261 | { 262 | smutils->LogError(myself, "Something went wrong with initing opus decoder: %i", err); 263 | return false; 264 | } 265 | 266 | return ConfigureDecoder(); 267 | } 268 | 269 | // Already initialized 270 | return true; 271 | } 272 | 273 | bool VoiceManager::ConfigureDecoder() 274 | { 275 | int err = opus_decoder_ctl(m_Opus_Decoder, OPUS_SET_GAIN(m_gain)); 276 | if (err < 0) 277 | { 278 | smutils->LogError(myself, "Something went wrong with initing opus decoder gain: %i", err); 279 | return false; 280 | } 281 | 282 | return true; 283 | } 284 | 285 | EncodedChunk VoiceManager::OpusEncode(DecodedChunk decoded) 286 | { 287 | EncodedChunk encoded; 288 | encoded.index = decoded.index; 289 | uint8_t x[MAX_PACKET_SIZE]; 290 | 291 | int compressedBytes = opus_encode(m_Opus_Encoder, decoded.data.data(), decoded.data.size(), x, (opus_int32)MAX_PACKET_SIZE); 292 | if (compressedBytes < 0) 293 | { 294 | smutils->LogError(myself, "Opus Encoder Failed with err: %s", ErrorToString(compressedBytes)); 295 | } 296 | 297 | encoded.data = std::vector(compressedBytes); 298 | for (int i = 0; i < compressedBytes; i++) 299 | { 300 | encoded.data[i] = x[i]; 301 | } 302 | 303 | return encoded; 304 | } 305 | 306 | DecodedChunk VoiceManager::OpusDecode(EncodedChunk encoded) 307 | { 308 | DecodedChunk decoded; 309 | decoded.index = encoded.index; 310 | int16_t x[MAX_PACKET_SIZE]; 311 | 312 | int samples = opus_decode(m_Opus_Decoder, encoded.data.data(), encoded.data.size(), x, MAX_FRAMEBUFFER_SAMPLES, 0); 313 | if (samples < 0) 314 | { 315 | smutils->LogError(myself, "Opus Decoder Failed: %s", ErrorToString(samples)); 316 | } 317 | 318 | decoded.data = std::vector(samples); 319 | for (int i = 0; i < samples; i++) 320 | { 321 | decoded.data[i] = x[i]; 322 | } 323 | 324 | return decoded; 325 | } 326 | 327 | const char* VoiceManager::ErrorToString(int error) 328 | { 329 | switch (error) 330 | { 331 | case OPUS_OK: 332 | return "OK"; 333 | case OPUS_BAD_ARG: 334 | return "One or more invalid/out of range arguments."; 335 | case OPUS_BUFFER_TOO_SMALL: 336 | return "The mode struct passed is invalid."; 337 | case OPUS_INTERNAL_ERROR: 338 | return "An internal error was detected."; 339 | case OPUS_INVALID_PACKET: 340 | return "The compressed data passed is corrupted."; 341 | case OPUS_UNIMPLEMENTED: 342 | return "Invalid/unsupported request number."; 343 | case OPUS_INVALID_STATE: 344 | return "An encoder or decoder structure is invalid or already freed."; 345 | default: 346 | return "Unknown error code"; 347 | } 348 | } -------------------------------------------------------------------------------- /extension/voicemanager.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "CRC.h" 5 | #include "smsdk_ext.h" 6 | #include 7 | #include "defines.h" 8 | 9 | struct EncodedChunk 10 | { 11 | int16_t index = 0; 12 | std::vector data; 13 | }; 14 | 15 | struct DecodedChunk 16 | { 17 | int16_t index = 0; 18 | std::vector data; 19 | }; 20 | 21 | class VoiceManager 22 | { 23 | 24 | private: 25 | std::vector m_vecDecodedChunks; 26 | opus_int32 m_sampleRate = 0; 27 | opus_int32 m_gain = 0; 28 | OpusDecoder* m_Opus_Decoder = nullptr; 29 | OpusEncoder* m_Opus_Encoder = nullptr; 30 | 31 | public: 32 | VoiceManager(); 33 | VoiceManager(opus_int32 gain); 34 | 35 | static void writeInt(std::ofstream& stream, const int& t) 36 | { 37 | stream.write((const char*)&t, sizeof(int)); 38 | } 39 | 40 | static void writeShort(std::ofstream& stream, const short& t) 41 | { 42 | stream.write((const char*)&t, sizeof(short)); 43 | } 44 | 45 | uint8_t* OnBroadcastVoiceData(IClient* pClient, int nBytes, const uint8_t* data, int* nBytesOut); 46 | void ParseSteamVoicePacket(uint8_t* bytes, int numBytes); 47 | bool InitOpusDecoder(opus_int32 rate); 48 | bool ConfigureDecoder(); 49 | bool InitOpusEncoder(opus_int32 rate); 50 | bool ConfigureEncoder(); 51 | DecodedChunk OpusDecode(EncodedChunk encodedData); 52 | EncodedChunk OpusEncode(DecodedChunk decodedChunk); 53 | const char* ErrorToString(int error); 54 | }; -------------------------------------------------------------------------------- /extension/voicemanagerclientstate.cpp: -------------------------------------------------------------------------------- 1 | #include "extension.h" 2 | 3 | VoiceManagerClientState::VoiceManagerClientState() 4 | { 5 | for (int level = 0; level < 4; level++) 6 | { 7 | opus_int32 gain; 8 | switch (level) 9 | { 10 | case 0: 11 | gain = LEVEL_QUIETER; 12 | break; 13 | case 1: 14 | gain = LEVEL_QUIET; 15 | break; 16 | case 2: 17 | gain = LEVEL_LOUD; 18 | break; 19 | case 3: 20 | gain = LEVEL_LOUDER; 21 | break; 22 | } 23 | 24 | m_manager[level] = VoiceManager(gain); 25 | } 26 | }; 27 | 28 | VoiceManager* VoiceManagerClientState::GetVoiceManager(int level) 29 | { 30 | return &m_manager[level]; 31 | } -------------------------------------------------------------------------------- /extension/voicemanagerclientstate.h: -------------------------------------------------------------------------------- 1 | #include "smsdk_ext.h" 2 | #include "voicemanager.h" 3 | #include 4 | 5 | class VoiceManagerClientState 6 | { 7 | private: 8 | VoiceManager m_manager[4]; 9 | 10 | public: 11 | VoiceManagerClientState(); 12 | VoiceManager* GetVoiceManager(int level); 13 | }; --------------------------------------------------------------------------------