diff --git a/.gitignore b/.gitignore index 2a93a87b90..b641ee933f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ docs/doxygen_sqlite3.db build buildtools/composer.phar src/build +cmake-build-debug # tests test diff --git a/docpages/install/install-vcpkg.md b/docpages/install/install-vcpkg.md index f7f44629f1..8ffcb00d78 100644 --- a/docpages/install/install-vcpkg.md +++ b/docpages/install/install-vcpkg.md @@ -1,19 +1,22 @@ -\page install-vcpkg Installing from VCPKG (Windows, Linux, OSX) +\page install-vcpkg Installing from VCPKG (Windows) -To install D++ on a system from VCPKG: +\warning **We do not support VCPKG for any platform that isn't Windows. This does not mean VCPKG doesn't work, it just means we do not test it.** If you are using other platforms then please look towards our other pages. We also advise that you use the [pre-made Visual Studio template](https://github.com/brainboxdotcc/windows-bot-template/) on Windows, as VCPKG takes longer to receive updates. + +To install D++ on a system with VCPKG: + +- Ensure VCPKG is correctly installed, and run `vcpkg integrate install` to integrate it with your preferred IDE. This has been reported to work with Visual Studio, VSCode, and JetBrains CLion. +- From a command line, type `vcpkg install dpp:x64-windows` -- Ensure VCPKG is correctly installed, and run `vcpkg integrate install` to integrate it with your preferred IDE. This has been reported to work with Visual Studio, vscode, and JetBrains CLion. -- From a command line, type `vcpkg install dpp:x64-windows` (replace `x64-windows` with whichever OS and architecture you want the library to be built for) \image html vcpkg.png -- VCPKG will install the library and dependencies for you! Once completed you will receive a message indicating success: -- Use `vcpkg list dpp` to check that the package is installed: -``` +- VCPKG will install the library, and dependencies, for you! Once completed, you will receive a message, indicating that dpp successfully installed! +- Use `vcpkg list dpp` to check that the package is installed, as so: +```cmd c:\vcpkg>vcpkg list dpp -dpp:x64-windows 10.0.15 D++ Extremely Lightweight C++ Discord Library. +dpp:x64-windows 10.0.24 D++ Extremely Lightweight C++ Discord Library. ``` - You may now use the library within a `CMake` based project by adding instructions such as these to your `CMakeLists.txt`: ```cmake - find_package(dpp CONFIG REQUIRED) - target_link_libraries(your_target_name PRIVATE dpp::dpp) +find_package(dpp CONFIG REQUIRED) +target_link_libraries(your_target_name PRIVATE dpp::dpp) ``` diff --git a/include/dpp/discordvoiceclient.h b/include/dpp/discordvoiceclient.h index eba704e337..39c5036356 100644 --- a/include/dpp/discordvoiceclient.h +++ b/include/dpp/discordvoiceclient.h @@ -50,14 +50,19 @@ #include #include - - struct OpusDecoder; struct OpusEncoder; struct OpusRepacketizer; namespace dpp { +// !TODO: change these to constexpr and rename every occurrence across the codebase +#define AUDIO_TRACK_MARKER (uint16_t)0xFFFF + +#define AUDIO_OVERLAP_SLEEP_SAMPLES 30 + +inline constexpr size_t send_audio_raw_max_length = 11520; + using json = nlohmann::json; /* @@ -95,10 +100,6 @@ struct DPP_EXPORT voice_out_packet { uint64_t duration; }; -#define AUDIO_TRACK_MARKER (uint16_t)0xFFFF - -#define AUDIO_OVERLAP_SLEEP_SAMPLES 30 - /** @brief Implements a discord voice connection. * Each discord_voice_client connects to one voice channel and derives from a websocket client. */ @@ -676,7 +677,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client /** * @brief Send raw audio to the voice channel. * - * You should send an audio packet of 11520 bytes. + * You should send an audio packet of `send_audio_raw_max_length` (11520) bytes. * Note that this function can be costly as it has to opus encode * the PCM audio on the fly, and also encrypt it with libsodium. * @@ -695,8 +696,16 @@ class DPP_EXPORT discord_voice_client : public websocket_client * * @param length The length of the audio data. The length should * be a multiple of 4 (2x 16 bit stereo channels) with a maximum - * length of 11520, which is a complete opus frame at highest - * quality. + * length of `send_audio_raw_max_length`, which is a complete opus + * frame at highest quality. + * + * Generally when you're streaming and you know there will be + * more packet to come you should always provide packet data with + * length of `send_audio_raw_max_length`. + * Silence packet will be appended if length is less than + * `send_audio_raw_max_length` as discord expects to receive such + * specific packet size. This can cause gaps in your stream resulting + * in distorted audio if you have more packet to send later on. * * @return discord_voice_client& Reference to self * diff --git a/library-vcpkg/CMakeLists.txt b/library-vcpkg/CMakeLists.txt index a33b18ccc0..a8377cf699 100644 --- a/library-vcpkg/CMakeLists.txt +++ b/library-vcpkg/CMakeLists.txt @@ -18,15 +18,19 @@ endif() target_compile_definitions( "${LIB_NAME}" PUBLIC "DPP_BUILD" - "$<$:$<$:/sdl;/std:c++17;/Od;/DEBUG;/sdl;/MP;/DFD_SETSIZE=1024;/Zc:preprocessor>>" - "$<$:$<$:/std:c++17;/O2;/Oi;/Oy;/GL;/Gy;/sdl;/MP;/DFD_SETSIZE=1024;/Zc:preprocessor>>" - "${AVX_TYPE}" ) +add_compile_definitions(OPENSSL_SYS_WIN32) +add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS) +add_compile_definitions(WIN32_LEAN_AND_MEAN) +add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +add_compile_definitions(_CRT_NONSTDC_NO_DEPRECATE) +add_compile_definitions(T_fallback) + target_compile_options( "${LIB_NAME}" PUBLIC "$<$:/bigobj>" - "$<$:$<$:/sdl;/std:c++17;/Od;/DEBUG;/sdl;/MP;/DFD_SETSIZE=1024;/Zc:preprocessor>>" + "$<$:$<$:/sdl;/std:c++17;/Od;/DEBUG;/MP;/DFD_SETSIZE=1024;/Zc:preprocessor>>" "$<$:$<$:/std:c++17;/O2;/Oi;/Oy;/GL;/Gy;/sdl;/MP;/DFD_SETSIZE=1024;/Zc:preprocessor>>" "$<$:$<$:-std=c++17;-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-g;-Og;-fPIC>>" "$<$:$<$:-std=c++17;-Wall;-Wempty-body;-Wno-psabi;-Wunknown-pragmas;-Wignored-qualifiers;-Wimplicit-fallthrough;-Wmissing-field-initializers;-Wsign-compare;-Wtype-limits;-Wuninitialized;-Wshift-negative-value;-pthread;-O3;-fPIC>>" diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 4f09992f72..efe729fe82 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -1166,20 +1166,34 @@ discord_voice_client& discord_voice_client::set_send_audio_type(send_audio_type_ discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, const size_t length) { #if HAVE_VOICE - const size_t max_frame_bytes = 11520; - if (length > max_frame_bytes) { + if (length < 4) { + throw dpp::voice_exception("Raw audio packet size can't be less than 4"); + } + + if ((length % 4) != 0) { + throw dpp::voice_exception("Raw audio packet size should be divisible by 4"); + } + + if (length > send_audio_raw_max_length) { std::string s_audio_data((const char*)audio_data, length); - while (s_audio_data.length() > max_frame_bytes) { - std::string packet(s_audio_data.substr(0, max_frame_bytes)); - s_audio_data.erase(s_audio_data.begin(), s_audio_data.begin() + max_frame_bytes); - if (packet.size() < max_frame_bytes) { - packet.resize(max_frame_bytes, 0); - } - send_audio_raw((uint16_t*)packet.data(), max_frame_bytes); + + while (s_audio_data.length() > send_audio_raw_max_length) { + std::string packet(s_audio_data.substr(0, send_audio_raw_max_length)); + const auto packet_size = static_cast(packet.size()); + + s_audio_data.erase(s_audio_data.begin(), s_audio_data.begin() + packet_size); + + send_audio_raw((uint16_t*)packet.data(), packet_size); } return *this; + } + + if (length < send_audio_raw_max_length) { + std::string packet((const char*)audio_data, length); + packet.resize(send_audio_raw_max_length, 0); + return send_audio_raw((uint16_t*)packet.data(), packet.size()); } opus_int32 encodedAudioMaxLength = (opus_int32)length; diff --git a/src/dpp/presence.cpp b/src/dpp/presence.cpp index bd27de1fa0..5a74fc8b93 100644 --- a/src/dpp/presence.cpp +++ b/src/dpp/presence.cpp @@ -72,7 +72,16 @@ presence::presence() : user_id(0), guild_id(0), flags(0) presence::presence(presence_status status, activity_type type, const std::string& activity_description) { dpp::activity a; + + /* Even if type is custom, a name is still required. + * We'll just set the name as this activity_description as it won't be used if custom either way. */ a.name = activity_description; + + /* If the type is custom, set the state as "activity_description" */ + if(type == activity_type::at_custom) { + a.state = activity_description; + } + a.type = type; activities.clear(); activities.emplace_back(a); @@ -254,7 +263,12 @@ std::string presence::build_json(bool with_id) const { { "type", i.type } }); if (!i.url.empty()) j2["url"] = i.url; - if (!i.state.empty()) j2["details"] = i.state; // bot activity is details, not state + + if(i.type == activity_type::at_custom) { + if (!i.state.empty()) j2["state"] = i.state; /* When type is custom, bot needs to use "state" */ + } else { + if (!i.state.empty()) j2["details"] = i.state; /* Otherwise, the bot needs to use "details" */ + } j["d"]["activities"].push_back(j2); }