diff --git a/components/spotify/CMakeLists.txt b/components/spotify/CMakeLists.txt index 1eaa59df..63c65cd4 100644 --- a/components/spotify/CMakeLists.txt +++ b/components/spotify/CMakeLists.txt @@ -17,6 +17,7 @@ set(BELL_DISABLE_SINKS ON) set(BELL_DISABLE_FMT ON) set(BELL_DISABLE_REGEX ON) set(BELL_ONLY_CJSON ON) +set(BELL_DISABLE_MQTT ON) set(CSPOT_TARGET_ESP32 ON) # because CMake is so broken, the cache set below overrides a normal "set" for the first build diff --git a/components/spotify/Shim.cpp b/components/spotify/Shim.cpp index eb30f70c..014d2f0d 100644 --- a/components/spotify/Shim.cpp +++ b/components/spotify/Shim.cpp @@ -34,78 +34,6 @@ static class cspotPlayer *player; -/**************************************************************************************** - * Chunk manager class (task) - */ - -class chunkManager : public bell::Task { -public: - std::atomic isRunning = true; - std::atomic isPaused = true; - chunkManager(std::function trackHandler, std::function dataHandler); - size_t writePCM(uint8_t* data, size_t bytes, std::string_view trackId, size_t sequence); - void flush(); - void teardown(); - -private: - std::unique_ptr centralAudioBuffer; - std::function trackHandler; - std::function dataHandler; - std::mutex runningMutex; - - void runTask() override; -}; - -chunkManager::chunkManager(std::function trackHandler, std::function dataHandler) - : bell::Task("chunker", 4 * 1024, 0, 0) { - this->centralAudioBuffer = std::make_unique(32); - this->trackHandler = trackHandler; - this->dataHandler = dataHandler; - startTask(); -} - -size_t chunkManager::writePCM(uint8_t* data, size_t bytes, std::string_view trackId, size_t sequence) { - return centralAudioBuffer->writePCM(data, bytes, sequence); -} - -void chunkManager::teardown() { - isRunning = false; - std::scoped_lock lock(runningMutex); -} - -void chunkManager::flush() { - centralAudioBuffer->clearBuffer(); -} - -void chunkManager::runTask() { - std::scoped_lock lock(runningMutex); - size_t lastHash = 0; - - while (isRunning) { - - if (isPaused) { - BELL_SLEEP_MS(100); - continue; - } - - auto chunk = centralAudioBuffer->readChunk(); - - if (!chunk || chunk->pcmSize == 0) { - BELL_SLEEP_MS(50); - continue; - } - - // receiving first chunk of new track from Spotify server - if (lastHash != chunk->trackHash) { - CSPOT_LOG(info, "hash update %x => %x", lastHash, chunk->trackHash); - lastHash = chunk->trackHash; - trackHandler(); - } - - dataHandler(chunk->pcmData, chunk->pcmSize); - } -} - /**************************************************************************************** * Player's main class & task */ @@ -114,19 +42,21 @@ class cspotPlayer : public bell::Task { private: std::string name; bell::WrappedSemaphore clientConnected; - + std::atomic isPaused, isConnected; + int startOffset, volume = 0, bitrate = 160; httpd_handle_t serverHandle; int serverPort; cspot_cmd_cb_t cmdHandler; cspot_data_cb_t dataHandler; + std::string lastTrackId; std::shared_ptr blob; std::unique_ptr spirc; - std::unique_ptr chunker; void eventHandler(std::unique_ptr event); void trackHandler(void); + size_t pcmWrite(uint8_t *pcm, size_t bytes, std::string_view trackId); void runTask(); @@ -155,6 +85,17 @@ cspotPlayer::cspotPlayer(const char* name, httpd_handle_t server, int port, cspo if (bitrate != 96 && bitrate != 160 && bitrate != 320) bitrate = 160; } +size_t cspotPlayer::pcmWrite(uint8_t *pcm, size_t bytes, std::string_view trackId) { + if (lastTrackId != trackId) { + CSPOT_LOG(info, "new track started <%s> => <%s>", lastTrackId.c_str(), trackId.data()); + lastTrackId = trackId; + trackHandler(); + } + + dataHandler(pcm, bytes); + return bytes; +} + extern "C" { static esp_err_t handleGET(httpd_req_t *request) { return player->handleGET(request); @@ -233,8 +174,7 @@ esp_err_t cspotPlayer::handlePOST(httpd_req_t *request) { void cspotPlayer::eventHandler(std::unique_ptr event) { switch (event->eventType) { case cspot::SpircHandler::EventType::PLAYBACK_START: { - chunker->flush(); - + lastTrackId.clear(); // we are not playing anymore trackStatus = TRACK_INIT; // memorize position for when track's beginning will be detected @@ -247,13 +187,12 @@ void cspotPlayer::eventHandler(std::unique_ptr event break; } case cspot::SpircHandler::EventType::PLAY_PAUSE: { - bool pause = std::get(event->data); - cmdHandler(pause ? CSPOT_PAUSE : CSPOT_PLAY); - chunker->isPaused = pause; + isPaused = std::get(event->data); + cmdHandler(isPaused ? CSPOT_PAUSE : CSPOT_PLAY); break; } case cspot::SpircHandler::EventType::TRACK_INFO: { - auto trackInfo = std::get(event->data); + auto trackInfo = std::get(event->data); cmdHandler(CSPOT_TRACK_INFO, trackInfo.duration, startOffset, trackInfo.artist.c_str(), trackInfo.album.c_str(), trackInfo.name.c_str(), trackInfo.imageUrl.c_str()); spirc->updatePositionMs(startOffset); @@ -264,17 +203,14 @@ void cspotPlayer::eventHandler(std::unique_ptr event case cspot::SpircHandler::EventType::PREV: case cspot::SpircHandler::EventType::FLUSH: { // FLUSH is sent when there is no next, just clean everything - chunker->flush(); cmdHandler(CSPOT_FLUSH); break; } case cspot::SpircHandler::EventType::DISC: - chunker->flush(); cmdHandler(CSPOT_DISC); - chunker->teardown(); + isConnected = false; break; case cspot::SpircHandler::EventType::SEEK: { - chunker->flush(); cmdHandler(CSPOT_SEEK, std::get(event->data)); break; } @@ -293,10 +229,9 @@ void cspotPlayer::eventHandler(std::unique_ptr event void cspotPlayer::trackHandler(void) { // this is just informative - auto trackInfo = spirc->getTrackPlayer()->getCurrentTrackInfo(); uint32_t remains; cmdHandler(CSPOT_QUERY_REMAINING, &remains); - CSPOT_LOG(info, "next track <%s> will play in %d ms", trackInfo.name.c_str(), remains); + CSPOT_LOG(info, "next track will play in %d ms", remains); // inform sink of track beginning trackStatus = TRACK_NOTIFY; @@ -317,7 +252,8 @@ void cspotPlayer::command(cspot_event_t event) { break; // setPause comes back through cspot::event with PLAY/PAUSE case CSPOT_TOGGLE: - spirc->setPause(!chunker->isPaused); + isPaused = !isPaused; + spirc->setPause(isPaused); break; case CSPOT_STOP: case CSPOT_PAUSE: @@ -326,12 +262,11 @@ void cspotPlayer::command(cspot_event_t event) { case CSPOT_PLAY: spirc->setPause(false); break; - // calling spirc->disconnect() might have been logical but it does not - // generate any cspot::event, so we need to manually force exiting player - // loop through chunker which will eventually do the disconnect + /* Calling spirc->disconnect() might have been logical but it does not + * generate any cspot::event */ case CSPOT_DISC: cmdHandler(CSPOT_DISC); - chunker->teardown(); + isConnected = false; break; // spirc->setRemoteVolume does not generate a cspot::event so call cmdHandler case CSPOT_VOLUME_UP: @@ -391,20 +326,12 @@ void cspotPlayer::runTask() { // Auth successful if (token.size() > 0) { spirc = std::make_unique(ctx); + isConnected = true; - // Create a player, pass the track handler - chunker = std::make_unique( - [this](void) { - return trackHandler(); - }, - [this](const uint8_t* data, size_t bytes) { - return dataHandler(data, bytes); - }); - // set call back to calculate a hash on trackId spirc->getTrackPlayer()->setDataCallback( - [this](uint8_t* data, size_t bytes, std::string_view trackId, size_t sequence) { - return chunker->writePCM(data, bytes, trackId, sequence); + [this](uint8_t* data, size_t bytes, std::string_view trackId) { + return pcmWrite(data, bytes, trackId); }); // set event (PLAY, VOLUME...) handler @@ -420,7 +347,7 @@ void cspotPlayer::runTask() { cmdHandler(CSPOT_VOLUME, volume); // exit when player has stopped (received a DISC) - while (chunker->isRunning) { + while (isConnected) { ctx->session->handlePacket(); // low-accuracy polling events diff --git a/components/spotify/cspot/bell/.clangd b/components/spotify/cspot/bell/.clangd index ffa67d1f..33c8b9b7 100644 --- a/components/spotify/cspot/bell/.clangd +++ b/components/spotify/cspot/bell/.clangd @@ -1,2 +1,3 @@ + CompileFlags: CompilationDatabase: example/build # Search build/ directory for compile_commands.json diff --git a/components/spotify/cspot/bell/CMakeLists.txt b/components/spotify/cspot/bell/CMakeLists.txt index 80af580b..d2aaab08 100644 --- a/components/spotify/cspot/bell/CMakeLists.txt +++ b/components/spotify/cspot/bell/CMakeLists.txt @@ -7,6 +7,7 @@ project(bell) option(BELL_DISABLE_CODECS "Disable the entire audio codec wrapper" OFF) option(BELL_CODEC_AAC "Support libhelix-aac codec" ON) option(BELL_CODEC_MP3 "Support libhelix-mp3 codec" ON) +option(BELL_DISABLE_MQTT "Disable the built-in MQTT wrapper" OFF) option(BELL_CODEC_VORBIS "Support tremor Vorbis codec" ON) option(BELL_CODEC_ALAC "Support Apple ALAC codec" ON) option(BELL_CODEC_OPUS "Support Opus codec" ON) @@ -63,13 +64,14 @@ endif() message(STATUS " Use cJSON only: ${BELL_ONLY_CJSON}") message(STATUS " Disable Fmt: ${BELL_DISABLE_FMT}") +message(STATUS " Disable Mqtt: ${BELL_DISABLE_MQTT}") message(STATUS " Disable Regex: ${BELL_DISABLE_REGEX}") # Include nanoPB library set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/external/nanopb/extra") find_package(Nanopb REQUIRED) message(${NANOPB_INCLUDE_DIRS}) -list(APPEND EXTRA_INCLUDES ${NANOPB_INCLUDE_DIRS}) +list(APPEND EXTERNAL_INCLUDES ${NANOPB_INCLUDE_DIRS}) # CMake options set(CMAKE_CXX_STANDARD 20) @@ -84,7 +86,7 @@ set(IO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/io") set(PLATFORM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/platform") set(UTILITIES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/utilities") -add_definitions("-DUSE_DEFAULT_STDLIB=1") +add_definitions("-DUSE_DEFAULT_STDLIB=1 -DTARGET_OS_IPHONE=0") # Main library sources file(GLOB SOURCES @@ -111,7 +113,7 @@ endif() if(APPLE) file(GLOB APPLE_PLATFORM_SOURCES "main/platform/apple/*.cpp" "main/platform/apple/*.c") list(APPEND SOURCES ${APPLE_PLATFORM_SOURCES}) - list(APPEND EXTRA_INCLUDES "/usr/local/opt/mbedtls@3/include") + list(APPEND EXTERNAL_INCLUDES "/usr/local/opt/mbedtls@3/include") endif() if(UNIX AND NOT APPLE) @@ -122,7 +124,7 @@ endif() if(WIN32) file(GLOB WIN32_PLATFORM_SOURCES "main/platform/win32/*.cpp" "main/platform/win32/*.c") list(APPEND SOURCES ${WIN32_PLATFORM_SOURCES}) - list(APPEND EXTRA_INCLUDES "main/platform/win32") + list(APPEND EXTERNAL_INCLUDES "main/platform/win32") endif() # A hack to make Opus keep quiet @@ -139,7 +141,7 @@ if(ESP_PLATFORM) else() find_package(Threads REQUIRED) find_package(MbedTLS REQUIRED) - list(APPEND EXTRA_INCLUDES ${MBEDTLS_INCLUDE_DIRS}) + list(APPEND EXTERNAL_INCLUDES ${MBEDTLS_INCLUDE_DIRS}) set(THREADS_PREFER_PTHREAD_FLAG ON) list(APPEND EXTRA_LIBS ${MBEDTLS_LIBRARIES} Threads::Threads) @@ -149,6 +151,14 @@ else() endif() endif() +if (NOT BELL_DISABLE_MQTT) + file(GLOB MQTT_SOURCES "external/mqtt/*.c") + list(APPEND SOURCES ${MQTT_SOURCES}) + list(APPEND EXTRA_INCLUDES "external/mqtt/include") +else() + list(REMOVE_ITEM SOURCES "${IO_DIR}/BellMQTTClient.cpp") +endif() + if(NOT BELL_DISABLE_CODECS) file(GLOB EXTRA_SOURCES "main/audio-containers/*.cpp" "main/audio-codec/*.cpp" "main/audio-codec/*.c" "main/audio-dsp/*.cpp" "main/audio-dsp/*.c") @@ -162,7 +172,7 @@ if(NOT BELL_DISABLE_CODECS) if(BELL_CODEC_AAC) file(GLOB LIBHELIX_AAC_SOURCES "external/libhelix-aac/*.c") list(APPEND LIBHELIX_SOURCES ${LIBHELIX_AAC_SOURCES}) - list(APPEND EXTRA_INCLUDES "external/libhelix-aac") + list(APPEND EXTERNAL_INCLUDES "external/libhelix-aac") list(APPEND SOURCES "${AUDIO_CODEC_DIR}/AACDecoder.cpp") list(APPEND CODEC_FLAGS "-DBELL_CODEC_AAC") endif() @@ -171,7 +181,7 @@ if(NOT BELL_DISABLE_CODECS) if(BELL_CODEC_MP3) file(GLOB LIBHELIX_MP3_SOURCES "external/libhelix-mp3/*.c") list(APPEND LIBHELIX_SOURCES ${LIBHELIX_MP3_SOURCES}) - list(APPEND EXTRA_INCLUDES "external/libhelix-mp3") + list(APPEND EXTERNAL_INCLUDES "external/libhelix-mp3") list(APPEND SOURCES "${AUDIO_CODEC_DIR}/MP3Decoder.cpp") list(APPEND CODEC_FLAGS "-DBELL_CODEC_MP3") endif() @@ -230,7 +240,7 @@ else() file(GLOB TREMOR_SOURCES "external/tremor/*.c") list(REMOVE_ITEM TREMOR_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/tremor/ivorbisfile_example.c") list(APPEND SOURCES ${TREMOR_SOURCES}) - list(APPEND EXTRA_INCLUDES "external/tremor") + list(APPEND EXTERNAL_INCLUDES "external/tremor") endif() if(NOT BELL_DISABLE_SINKS) @@ -247,7 +257,7 @@ if(NOT BELL_DISABLE_SINKS) # Find ALSA if required, else remove the sink if(BELL_SINK_ALSA) find_package(ALSA REQUIRED) - list(APPEND EXTRA_INCLUDES ${ALSA_INCLUDE_DIRS}) + list(APPEND EXTERNAL_INCLUDES ${ALSA_INCLUDE_DIRS}) list(APPEND EXTRA_LIBS ${ALSA_LIBRARIES}) else() list(REMOVE_ITEM SINK_SOURCES "${AUDIO_SINKS_DIR}/unix/ALSAAudioSink.cpp") @@ -256,7 +266,7 @@ if(NOT BELL_DISABLE_SINKS) # Find PortAudio if required, else remove the sink if(BELL_SINK_PORTAUDIO) find_package(Portaudio REQUIRED) - list(APPEND EXTRA_INCLUDES ${PORTAUDIO_INCLUDE_DIRS}) + list(APPEND EXTERNAL_INCLUDES ${PORTAUDIO_INCLUDE_DIRS}) list(APPEND EXTRA_LIBS ${PORTAUDIO_LIBRARIES}) else() list(REMOVE_ITEM SINK_SOURCES "${AUDIO_SINKS_DIR}/unix/PortAudioSink.cpp") @@ -274,16 +284,16 @@ if(BELL_EXTERNAL_CJSON) list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_CJSON}) else() list(APPEND SOURCES "external/cJSON/cJSON.c") - list(APPEND EXTRA_INCLUDES "external/cJSON") + list(APPEND EXTERNAL_INCLUDES "external/cJSON") endif() if (NOT BELL_DISABLE_FMT) - list(APPEND EXTRA_INCLUDES "external/fmt/include") + list(APPEND EXTERNAL_INCLUDES "external/fmt/include") endif() if(WIN32 OR UNIX) list(APPEND SOURCES "external/mdnssvc/mdns.c" "external/mdnssvc/mdnsd.c") - list(APPEND EXTRA_INCLUDES "external/mdnssvc") + list(APPEND EXTERNAL_INCLUDES "external/mdnssvc") endif() # file(GLOB CIVET_SRC "external/civetweb/*.c" "external/civetweb/*.inl" "external/civetweb/*.cpp") @@ -305,6 +315,7 @@ endif() # PUBLIC to propagate esp-idf includes to bell dependents target_link_libraries(bell PUBLIC ${EXTRA_LIBS}) target_include_directories(bell PUBLIC ${EXTRA_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(bell SYSTEM PUBLIC ${EXTERNAL_INCLUDES}) target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC FMT_HEADER_ONLY) if(BELL_DISABLE_CODECS) diff --git a/components/spotify/cspot/bell/example/CMakeLists.txt b/components/spotify/cspot/bell/example/CMakeLists.txt index 4e1466fc..29fee79b 100644 --- a/components/spotify/cspot/bell/example/CMakeLists.txt +++ b/components/spotify/cspot/bell/example/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.18) set(CMAKE_CXX_STANDARD 20) set(CMAKE_BUILD_TYPE Debug) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - +set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ ${CMAKE_CURRENT_BINARY_DIR}/bell) file(GLOB SOURCES "*.cpp") diff --git a/components/spotify/cspot/bell/example/main.cpp b/components/spotify/cspot/bell/example/main.cpp index 6d3a6129..0f043125 100644 --- a/components/spotify/cspot/bell/example/main.cpp +++ b/components/spotify/cspot/bell/example/main.cpp @@ -1,26 +1,14 @@ -#include #include -#include -#include -#include -#include #include -#include -#include "AudioCodecs.h" -#include "AudioContainers.h" -#include "BellHTTPServer.h" -#include "BellTar.h" +#include +#include + #include "BellTask.h" #include "CentralAudioBuffer.h" -#include "Compressor.h" -#include "DecoderGlobals.h" -#include "EncodedAudioStream.h" -#include "HTTPClient.h" #include "PortAudioSink.h" -#define DEBUG_LEVEL 4 -#include "X509Bundle.h" -#include "mbedtls/debug.h" +#include "StreamInfo.h" +#define DEBUG_LEVEL 4 #include #include @@ -58,13 +46,8 @@ class AudioPlayer : bell::Task { int main() { bell::setDefaultLogger(); - std::fstream file("system.tar", std::ios::in | std::ios::binary); - if (!file.is_open()) { - std::cout << "file not open" << std::endl; - return 1; - } - BellTar::reader reader(file); - reader.extract_all_files("./dupa2"); + BELL_LOG(info, "cock", "Published?"); + return 0; } diff --git a/components/spotify/cspot/bell/main/audio-codec/AACDecoder.cpp b/components/spotify/cspot/bell/main/audio-codec/AACDecoder.cpp index bf8d9d25..b6565b97 100644 --- a/components/spotify/cspot/bell/main/audio-codec/AACDecoder.cpp +++ b/components/spotify/cspot/bell/main/audio-codec/AACDecoder.cpp @@ -1,5 +1,12 @@ #include "AACDecoder.h" -#include + +#include // for free, malloc + +#include "CodecType.h" // for bell + +namespace bell { +class AudioContainer; +} // namespace bell using namespace bell; diff --git a/components/spotify/cspot/bell/main/audio-codec/AudioCodecs.cpp b/components/spotify/cspot/bell/main/audio-codec/AudioCodecs.cpp index 71215997..a21e513a 100644 --- a/components/spotify/cspot/bell/main/audio-codec/AudioCodecs.cpp +++ b/components/spotify/cspot/bell/main/audio-codec/AudioCodecs.cpp @@ -1,27 +1,37 @@ #include "AudioCodecs.h" -#include -#include -#include + +#include // for map, operator!=, map<>::iterator, map<>:... +#include // for remove_extent_t + +#include "AudioContainer.h" // for AudioContainer + +namespace bell { +class BaseCodec; +} // namespace bell using namespace bell; #ifdef BELL_CODEC_AAC -#include "AACDecoder.h" +#include "AACDecoder.h" // for AACDecoder + static std::shared_ptr codecAac; #endif #ifdef BELL_CODEC_MP3 -#include "MP3Decoder.h" +#include "MP3Decoder.h" // for MP3Decoder + static std::shared_ptr codecMp3; #endif #ifdef BELL_CODEC_VORBIS -#include "VorbisDecoder.h" +#include "VorbisDecoder.h" // for VorbisDecoder + static std::shared_ptr codecVorbis; #endif #ifdef BELL_CODEC_OPUS -#include "OPUSDecoder.h" +#include "OPUSDecoder.h" // for OPUSDecoder + static std::shared_ptr codecOpus; #endif diff --git a/components/spotify/cspot/bell/main/audio-codec/BaseCodec.cpp b/components/spotify/cspot/bell/main/audio-codec/BaseCodec.cpp index 12c38a71..46d5f8ad 100644 --- a/components/spotify/cspot/bell/main/audio-codec/BaseCodec.cpp +++ b/components/spotify/cspot/bell/main/audio-codec/BaseCodec.cpp @@ -1,5 +1,7 @@ #include "BaseCodec.h" -#include + +#include "AudioContainer.h" // for AudioContainer +#include "CodecType.h" // for bell using namespace bell; diff --git a/components/spotify/cspot/bell/main/audio-codec/DecoderGlobals.cpp b/components/spotify/cspot/bell/main/audio-codec/DecoderGlobals.cpp index f7c04e5e..037a5a30 100644 --- a/components/spotify/cspot/bell/main/audio-codec/DecoderGlobals.cpp +++ b/components/spotify/cspot/bell/main/audio-codec/DecoderGlobals.cpp @@ -2,7 +2,6 @@ bell::DecodersInstance* bell::decodersInstance; -void bell::createDecoders() -{ - bell::decodersInstance = new bell::DecodersInstance(); +void bell::createDecoders() { + bell::decodersInstance = new bell::DecodersInstance(); } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-codec/MP3Decoder.cpp b/components/spotify/cspot/bell/main/audio-codec/MP3Decoder.cpp index 7a5713a4..5293d0ef 100644 --- a/components/spotify/cspot/bell/main/audio-codec/MP3Decoder.cpp +++ b/components/spotify/cspot/bell/main/audio-codec/MP3Decoder.cpp @@ -1,5 +1,13 @@ #include "MP3Decoder.h" +#include // for free, malloc + +#include "CodecType.h" // for bell + +namespace bell { +class AudioContainer; +} // namespace bell + using namespace bell; MP3Decoder::MP3Decoder() { diff --git a/components/spotify/cspot/bell/main/audio-codec/OPUSDecoder.cpp b/components/spotify/cspot/bell/main/audio-codec/OPUSDecoder.cpp index 5c3d77d9..0bd3529b 100644 --- a/components/spotify/cspot/bell/main/audio-codec/OPUSDecoder.cpp +++ b/components/spotify/cspot/bell/main/audio-codec/OPUSDecoder.cpp @@ -1,5 +1,9 @@ #include "OPUSDecoder.h" -#include "opus.h" + +#include // for free, malloc + +#include "CodecType.h" // for bell +#include "opus.h" // for opus_decoder_destroy, opus_decode, opus_decod... using namespace bell; diff --git a/components/spotify/cspot/bell/main/audio-codec/VorbisDecoder.cpp b/components/spotify/cspot/bell/main/audio-codec/VorbisDecoder.cpp index a2fc685d..a4902fad 100644 --- a/components/spotify/cspot/bell/main/audio-codec/VorbisDecoder.cpp +++ b/components/spotify/cspot/bell/main/audio-codec/VorbisDecoder.cpp @@ -1,5 +1,13 @@ #include "VorbisDecoder.h" -#include "AudioCodecs.h" + +#include // for free, malloc + +#include "CodecType.h" // for bell +#include "config_types.h" // for ogg_int16_t + +namespace bell { +class AudioContainer; +} // namespace bell using namespace bell; diff --git a/components/spotify/cspot/bell/main/audio-codec/include/AACDecoder.h b/components/spotify/cspot/bell/main/audio-codec/include/AACDecoder.h index 6c1c7eab..e44b101c 100644 --- a/components/spotify/cspot/bell/main/audio-codec/include/AACDecoder.h +++ b/components/spotify/cspot/bell/main/audio-codec/include/AACDecoder.h @@ -1,9 +1,12 @@ #pragma once -#include "BaseCodec.h" -#include "aacdec.h" +#include // for uint8_t, uint32_t, int16_t + +#include "BaseCodec.h" // for BaseCodec +#include "aacdec.h" // for AACFrameInfo, HAACDecoder namespace bell { +class AudioContainer; class AACDecoder : public BaseCodec { private: diff --git a/components/spotify/cspot/bell/main/audio-codec/include/AudioCodecs.h b/components/spotify/cspot/bell/main/audio-codec/include/AudioCodecs.h index a230cb1a..2d5de6a7 100644 --- a/components/spotify/cspot/bell/main/audio-codec/include/AudioCodecs.h +++ b/components/spotify/cspot/bell/main/audio-codec/include/AudioCodecs.h @@ -1,11 +1,12 @@ #pragma once -#include -#include "BaseCodec.h" -#include "AudioContainer.h" +#include // for shared_ptr + +#include "AudioContainer.h" // for AudioContainer +#include "BaseCodec.h" // for BaseCodec +#include "CodecType.h" // for AudioCodec namespace bell { - class AudioCodecs { public: static std::shared_ptr getCodec(AudioCodec type); diff --git a/components/spotify/cspot/bell/main/audio-codec/include/BaseCodec.h b/components/spotify/cspot/bell/main/audio-codec/include/BaseCodec.h index 59d533ab..8d6270bf 100644 --- a/components/spotify/cspot/bell/main/audio-codec/include/BaseCodec.h +++ b/components/spotify/cspot/bell/main/audio-codec/include/BaseCodec.h @@ -1,8 +1,9 @@ #pragma once -#include "AudioContainer.h" +#include // for uint32_t, uint8_t namespace bell { +class AudioContainer; class BaseCodec { private: diff --git a/components/spotify/cspot/bell/main/audio-codec/include/DecoderGlobals.h b/components/spotify/cspot/bell/main/audio-codec/include/DecoderGlobals.h index 5a03a3a5..f8335a25 100644 --- a/components/spotify/cspot/bell/main/audio-codec/include/DecoderGlobals.h +++ b/components/spotify/cspot/bell/main/audio-codec/include/DecoderGlobals.h @@ -5,48 +5,40 @@ #define AAC_READBUF_SIZE (4 * AAC_MAINBUF_SIZE * AAC_MAX_NCHANS) #define MP3_READBUF_SIZE (2 * 1024); -#include -#include -#include -#include "aacdec.h" -#include "mp3dec.h" +#include // for NULL -namespace bell -{ - class DecodersInstance - { - public: - DecodersInstance(){}; - ~DecodersInstance() - { - MP3FreeDecoder(mp3Decoder); - AACFreeDecoder(aacDecoder); - }; +#include "aacdec.h" // for AACFreeDecoder, AACInitDecoder, HAACDecoder +#include "mp3dec.h" // for MP3FreeDecoder, MP3InitDecoder, HMP3Decoder - HAACDecoder aacDecoder = NULL; - HMP3Decoder mp3Decoder = NULL; +namespace bell { +class DecodersInstance { + public: + DecodersInstance(){}; + ~DecodersInstance() { + MP3FreeDecoder(mp3Decoder); + AACFreeDecoder(aacDecoder); + }; - void ensureAAC() - { - if (aacDecoder == NULL) - { - aacDecoder = AACInitDecoder(); - } - } + HAACDecoder aacDecoder = NULL; + HMP3Decoder mp3Decoder = NULL; - void ensureMP3() - { - if (mp3Decoder == NULL) - { - mp3Decoder = MP3InitDecoder(); - } - } - }; + void ensureAAC() { + if (aacDecoder == NULL) { + aacDecoder = AACInitDecoder(); + } + } - extern bell::DecodersInstance* decodersInstance; + void ensureMP3() { + if (mp3Decoder == NULL) { + mp3Decoder = MP3InitDecoder(); + } + } +}; - void createDecoders(); -} +extern bell::DecodersInstance* decodersInstance; + +void createDecoders(); +} // namespace bell #endif #endif diff --git a/components/spotify/cspot/bell/main/audio-codec/include/MP3Decoder.h b/components/spotify/cspot/bell/main/audio-codec/include/MP3Decoder.h index a9509c57..f38df171 100644 --- a/components/spotify/cspot/bell/main/audio-codec/include/MP3Decoder.h +++ b/components/spotify/cspot/bell/main/audio-codec/include/MP3Decoder.h @@ -1,9 +1,13 @@ #pragma once -#include "BaseCodec.h" -#include "mp3dec.h" +#include // for uint8_t, uint32_t, int16_t + +#include "BaseCodec.h" // for BaseCodec +#include "mp3dec.h" // for HMP3Decoder, MP3FrameInfo namespace bell { +class AudioContainer; + class MP3Decoder : public BaseCodec { private: HMP3Decoder mp3; diff --git a/components/spotify/cspot/bell/main/audio-codec/include/OPUSDecoder.h b/components/spotify/cspot/bell/main/audio-codec/include/OPUSDecoder.h index 13780d20..49c78ca7 100644 --- a/components/spotify/cspot/bell/main/audio-codec/include/OPUSDecoder.h +++ b/components/spotify/cspot/bell/main/audio-codec/include/OPUSDecoder.h @@ -1,6 +1,8 @@ #pragma once -#include "BaseCodec.h" +#include // for uint8_t, uint32_t, int16_t + +#include "BaseCodec.h" // for BaseCodec struct OpusDecoder; diff --git a/components/spotify/cspot/bell/main/audio-codec/include/VorbisDecoder.h b/components/spotify/cspot/bell/main/audio-codec/include/VorbisDecoder.h index 05a8d030..f7ed6285 100644 --- a/components/spotify/cspot/bell/main/audio-codec/include/VorbisDecoder.h +++ b/components/spotify/cspot/bell/main/audio-codec/include/VorbisDecoder.h @@ -1,9 +1,14 @@ #pragma once -#include "BaseCodec.h" -#include "ivorbiscodec.h" +#include // for uint8_t, uint32_t, int16_t + +#include "BaseCodec.h" // for BaseCodec +#include "ivorbiscodec.h" // for vorbis_comment, vorbis_dsp_state, vorbis_info +#include "ogg.h" // for ogg_packet namespace bell { +class AudioContainer; + class VorbisDecoder : public BaseCodec { private: vorbis_info* vi = nullptr; diff --git a/components/spotify/cspot/bell/main/audio-containers/AACContainer.cpp b/components/spotify/cspot/bell/main/audio-containers/AACContainer.cpp index b4c8f18f..314fd999 100644 --- a/components/spotify/cspot/bell/main/audio-containers/AACContainer.cpp +++ b/components/spotify/cspot/bell/main/audio-containers/AACContainer.cpp @@ -1,5 +1,10 @@ #include "AACContainer.h" -#include "iostream" + +#include // for memmove + +#include "StreamInfo.h" // for BitWidth, BitWidth::BW_16, SampleRate, Sampl... +#include "aacdec.h" // for AACFindSyncWord + using namespace bell; #define SYNC_WORLD_LEN 4 diff --git a/components/spotify/cspot/bell/main/audio-containers/AudioContainers.cpp b/components/spotify/cspot/bell/main/audio-containers/AudioContainers.cpp index 68940a51..bd8f45b5 100644 --- a/components/spotify/cspot/bell/main/audio-containers/AudioContainers.cpp +++ b/components/spotify/cspot/bell/main/audio-containers/AudioContainers.cpp @@ -1,5 +1,16 @@ #include "AudioContainers.h" +#include // for memcmp +#include // for byte + +#include "AACContainer.h" // for AACContainer +#include "CodecType.h" // for bell +#include "MP3Container.h" // for MP3Container + +namespace bell { +class AudioContainer; +} // namespace bell + using namespace bell; std::unique_ptr AudioContainers::guessAudioContainer( @@ -7,8 +18,7 @@ std::unique_ptr AudioContainers::guessAudioContainer( std::byte tmp[14]; istr.read((char*)tmp, sizeof(tmp)); - if (memcmp(tmp, "\xFF\xF1", 2) == 0 || - memcmp(tmp, "\xFF\xF9", 2) == 0) { + if (memcmp(tmp, "\xFF\xF1", 2) == 0 || memcmp(tmp, "\xFF\xF9", 2) == 0) { // AAC found std::cout << "AAC" << std::endl; return std::make_unique(istr); diff --git a/components/spotify/cspot/bell/main/audio-containers/MP3Container.cpp b/components/spotify/cspot/bell/main/audio-containers/MP3Container.cpp index 08629464..98bb6b66 100644 --- a/components/spotify/cspot/bell/main/audio-containers/MP3Container.cpp +++ b/components/spotify/cspot/bell/main/audio-containers/MP3Container.cpp @@ -1,5 +1,10 @@ #include "MP3Container.h" +#include // for memmove + +#include "StreamInfo.h" // for BitWidth, BitWidth::BW_16, SampleRate, Sampl... +#include "mp3dec.h" // for MP3FindSyncWord + using namespace bell; MP3Container::MP3Container(std::istream& istr) : bell::AudioContainer(istr) {} diff --git a/components/spotify/cspot/bell/main/audio-containers/include/AACContainer.h b/components/spotify/cspot/bell/main/audio-containers/include/AACContainer.h index d283c0c1..da8d9443 100644 --- a/components/spotify/cspot/bell/main/audio-containers/include/AACContainer.h +++ b/components/spotify/cspot/bell/main/audio-containers/include/AACContainer.h @@ -1,10 +1,12 @@ #pragma once -#include -#include -#include -#include "AudioContainer.h" -#include "aacdec.h" +#include // for uint32_t +#include // for byte, size_t +#include // for istream +#include // for vector + +#include "AudioContainer.h" // for AudioContainer +#include "CodecType.h" // for AudioCodec, AudioCodec::AAC namespace bell { class AACContainer : public AudioContainer { diff --git a/components/spotify/cspot/bell/main/audio-containers/include/AudioContainer.h b/components/spotify/cspot/bell/main/audio-containers/include/AudioContainer.h index 38648a0e..2c25cb96 100644 --- a/components/spotify/cspot/bell/main/audio-containers/include/AudioContainer.h +++ b/components/spotify/cspot/bell/main/audio-containers/include/AudioContainer.h @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include "CodecType.h" #include "StreamInfo.h" diff --git a/components/spotify/cspot/bell/main/audio-containers/include/AudioContainers.h b/components/spotify/cspot/bell/main/audio-containers/include/AudioContainers.h index a4c0e3af..a6369e1f 100644 --- a/components/spotify/cspot/bell/main/audio-containers/include/AudioContainers.h +++ b/components/spotify/cspot/bell/main/audio-containers/include/AudioContainers.h @@ -1,10 +1,11 @@ #pragma once -#include -#include -#include "AACContainer.h" -#include "AudioContainer.h" -#include "MP3Container.h" +#include // for istream +#include // for unique_ptr + +namespace bell { +class AudioContainer; +} // namespace bell namespace bell::AudioContainers { std::unique_ptr guessAudioContainer(std::istream& istr); diff --git a/components/spotify/cspot/bell/main/audio-containers/include/MP3Container.h b/components/spotify/cspot/bell/main/audio-containers/include/MP3Container.h index 028e17b6..d4bbfd0e 100644 --- a/components/spotify/cspot/bell/main/audio-containers/include/MP3Container.h +++ b/components/spotify/cspot/bell/main/audio-containers/include/MP3Container.h @@ -1,10 +1,12 @@ #pragma once -#include -#include -#include -#include "AudioContainer.h" -#include "mp3dec.h" +#include // for uint32_t +#include // for byte, size_t +#include // for istream +#include // for vector + +#include "AudioContainer.h" // for AudioContainer +#include "CodecType.h" // for AudioCodec, AudioCodec::MP3 namespace bell { class MP3Container : public AudioContainer { diff --git a/components/spotify/cspot/bell/main/audio-dsp/AudioMixer.cpp b/components/spotify/cspot/bell/main/audio-dsp/AudioMixer.cpp index 1c0c486a..fd0f7e4d 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/AudioMixer.cpp +++ b/components/spotify/cspot/bell/main/audio-dsp/AudioMixer.cpp @@ -1,39 +1,44 @@ #include "AudioMixer.h" +#include // for scoped_lock + using namespace bell; -AudioMixer::AudioMixer() { -} +AudioMixer::AudioMixer() {} -std::unique_ptr AudioMixer::process(std::unique_ptr info) { - std::scoped_lock lock(this->accessMutex); - if (info->numChannels != from) { - throw std::runtime_error("AudioMixer: Input channel count does not match configuration"); - } - info->numChannels = to; +std::unique_ptr AudioMixer::process( + std::unique_ptr info) { + std::scoped_lock lock(this->accessMutex); + if (info->numChannels != from) { + throw std::runtime_error( + "AudioMixer: Input channel count does not match configuration"); + } + info->numChannels = to; - for (auto &singleConf : mixerConfig) { - if (singleConf.source.size() == 1) { - if (singleConf.source[0] == singleConf.destination) { - continue; - } - // Copy channel - for (int i = 0; i < info->numSamples; i++) { - info->data[singleConf.destination][i] = info->data[singleConf.source[0]][i]; - } - } else { - // Mix channels - float sample = 0.0f; - for (int i = 0; i < info->numSamples; i++) { - sample = 0.0; - for (auto &source : singleConf.source) { - sample += info->data[source][i]; - } - - info->data[singleConf.destination][i] = sample / (float) singleConf.source.size(); - } + for (auto& singleConf : mixerConfig) { + if (singleConf.source.size() == 1) { + if (singleConf.source[0] == singleConf.destination) { + continue; + } + // Copy channel + for (int i = 0; i < info->numSamples; i++) { + info->data[singleConf.destination][i] = + info->data[singleConf.source[0]][i]; + } + } else { + // Mix channels + float sample = 0.0f; + for (int i = 0; i < info->numSamples; i++) { + sample = 0.0; + for (auto& source : singleConf.source) { + sample += info->data[source][i]; } - } - return info; + info->data[singleConf.destination][i] = + sample / (float)singleConf.source.size(); + } + } + } + + return info; } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/AudioPipeline.cpp b/components/spotify/cspot/bell/main/audio-dsp/AudioPipeline.cpp index 23b39fc5..853e1f2b 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/AudioPipeline.cpp +++ b/components/spotify/cspot/bell/main/audio-dsp/AudioPipeline.cpp @@ -1,47 +1,53 @@ #include "AudioPipeline.h" -#include -#include "BellLogger.h" + +#include // for remove_extent_t +#include // for move + +#include "AudioTransform.h" // for AudioTransform +#include "BellLogger.h" // for AbstractLogger, BELL_LOG +#include "TransformConfig.h" // for TransformConfig using namespace bell; -AudioPipeline::AudioPipeline() { +AudioPipeline::AudioPipeline(){ // this->headroomGainTransform = std::make_shared(Channels::LEFT_RIGHT); // this->transforms.push_back(this->headroomGainTransform); }; void AudioPipeline::addTransform(std::shared_ptr transform) { - transforms.push_back(transform); - recalculateHeadroom(); + transforms.push_back(transform); + recalculateHeadroom(); } void AudioPipeline::recalculateHeadroom() { - float headroom = 0.0f; + float headroom = 0.0f; - // Find largest headroom required by any transform down the chain, and apply it - for (auto transform : transforms) { - if (headroom < transform->calculateHeadroom()) { - headroom = transform->calculateHeadroom(); - } + // Find largest headroom required by any transform down the chain, and apply it + for (auto transform : transforms) { + if (headroom < transform->calculateHeadroom()) { + headroom = transform->calculateHeadroom(); } + } - // headroomGainTransform->configure(-headroom); + // headroomGainTransform->configure(-headroom); } void AudioPipeline::volumeUpdated(int volume) { - BELL_LOG(debug, "AudioPipeline", "Requested"); - std::scoped_lock lock(this->accessMutex); - for (auto transform : transforms) { - transform->config->currentVolume = volume; - transform->reconfigure(); - } - BELL_LOG(debug, "AudioPipeline", "Volume applied, DSP reconfigured"); + BELL_LOG(debug, "AudioPipeline", "Requested"); + std::scoped_lock lock(this->accessMutex); + for (auto transform : transforms) { + transform->config->currentVolume = volume; + transform->reconfigure(); + } + BELL_LOG(debug, "AudioPipeline", "Volume applied, DSP reconfigured"); } -std::unique_ptr AudioPipeline::process(std::unique_ptr data) { - std::scoped_lock lock(this->accessMutex); - for (auto &transform : transforms) { - data = transform->process(std::move(data)); - } +std::unique_ptr AudioPipeline::process( + std::unique_ptr data) { + std::scoped_lock lock(this->accessMutex); + for (auto& transform : transforms) { + data = transform->process(std::move(data)); + } - return data; + return data; } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/BellDSP.cpp b/components/spotify/cspot/bell/main/audio-dsp/BellDSP.cpp index 56d1d3ac..d6f04272 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/BellDSP.cpp +++ b/components/spotify/cspot/bell/main/audio-dsp/BellDSP.cpp @@ -1,6 +1,10 @@ #include "BellDSP.h" -#include -#include "CentralAudioBuffer.h" + +#include // for remove_extent_t +#include // for move + +#include "AudioPipeline.h" // for CentralAudioBuffer +#include "CentralAudioBuffer.h" // for CentralAudioBuffer using namespace bell; diff --git a/components/spotify/cspot/bell/main/audio-dsp/Biquad.cpp b/components/spotify/cspot/bell/main/audio-dsp/Biquad.cpp index 20391fa0..858593bd 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/Biquad.cpp +++ b/components/spotify/cspot/bell/main/audio-dsp/Biquad.cpp @@ -1,466 +1,439 @@ #include "Biquad.h" +#include // for pow, cosf, sinf, M_PI, sqrtf, tanf, logf, sinh + using namespace bell; -Biquad::Biquad() -{ - this->filterType = "biquad"; +Biquad::Biquad() { + this->filterType = "biquad"; } -void Biquad::sampleRateChanged(uint32_t sampleRate) -{ - this->sampleRate = sampleRate; - //this->configure(this->type, this->currentConfig); +void Biquad::sampleRateChanged(uint32_t sampleRate) { + this->sampleRate = sampleRate; + //this->configure(this->type, this->currentConfig); } -void Biquad::configure(Type type, std::map &newConf) -{ - this->type = type; - this->currentConfig = newConf; +void Biquad::configure(Type type, std::map& newConf) { + this->type = type; + this->currentConfig = newConf; - switch (type) - { + switch (type) { case Type::Free: - coeffs[0] = newConf["a1"]; - coeffs[1] = newConf["a2"]; - coeffs[2] = newConf["b0"]; - coeffs[3] = newConf["b1"]; - coeffs[4] = newConf["b2"]; - break; + coeffs[0] = newConf["a1"]; + coeffs[1] = newConf["a2"]; + coeffs[2] = newConf["b0"]; + coeffs[3] = newConf["b1"]; + coeffs[4] = newConf["b2"]; + break; case Type::Highpass: - highPassCoEffs(newConf["freq"], newConf["q"]); - break; + highPassCoEffs(newConf["freq"], newConf["q"]); + break; case Type::HighpassFO: - highPassFOCoEffs(newConf["freq"]); - break; + highPassFOCoEffs(newConf["freq"]); + break; case Type::Lowpass: - lowPassCoEffs(newConf["freq"], newConf["q"]); - break; + lowPassCoEffs(newConf["freq"], newConf["q"]); + break; case Type::LowpassFO: - lowPassFOCoEffs(newConf["freq"]); - break; + lowPassFOCoEffs(newConf["freq"]); + break; case Type::Highshelf: - // check if config has slope key - if (newConf.find("slope") != newConf.end()) - { - highShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]); - } - else - { - highShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); - } - break; + // check if config has slope key + if (newConf.find("slope") != newConf.end()) { + highShelfCoEffsSlope(newConf["freq"], newConf["gain"], + newConf["slope"]); + } else { + highShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); + } + break; case Type::HighshelfFO: - highShelfFOCoEffs(newConf["freq"], newConf["gain"]); - break; + highShelfFOCoEffs(newConf["freq"], newConf["gain"]); + break; case Type::Lowshelf: - // check if config has slope key - if (newConf.find("slope") != newConf.end()) - { - lowShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]); - } - else - { - lowShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); - } - break; + // check if config has slope key + if (newConf.find("slope") != newConf.end()) { + lowShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]); + } else { + lowShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); + } + break; case Type::LowshelfFO: - lowShelfFOCoEffs(newConf["freq"], newConf["gain"]); - break; + lowShelfFOCoEffs(newConf["freq"], newConf["gain"]); + break; case Type::Peaking: - // check if config has bandwidth key - if (newConf.find("bandwidth") != newConf.end()) - { - peakCoEffsBandwidth(newConf["freq"], newConf["gain"], newConf["bandwidth"]); - } - else - { - peakCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); - } - break; + // check if config has bandwidth key + if (newConf.find("bandwidth") != newConf.end()) { + peakCoEffsBandwidth(newConf["freq"], newConf["gain"], + newConf["bandwidth"]); + } else { + peakCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); + } + break; case Type::Notch: - if (newConf.find("bandwidth") != newConf.end()) - { - notchCoEffsBandwidth(newConf["freq"], newConf["gain"], newConf["bandwidth"]); - } - else - { - notchCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); - } - break; + if (newConf.find("bandwidth") != newConf.end()) { + notchCoEffsBandwidth(newConf["freq"], newConf["gain"], + newConf["bandwidth"]); + } else { + notchCoEffs(newConf["freq"], newConf["gain"], newConf["q"]); + } + break; case Type::Bandpass: - if (newConf.find("bandwidth") != newConf.end()) - { - bandPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]); - } - else - { - bandPassCoEffs(newConf["freq"], newConf["q"]); - } - break; + if (newConf.find("bandwidth") != newConf.end()) { + bandPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]); + } else { + bandPassCoEffs(newConf["freq"], newConf["q"]); + } + break; case Type::Allpass: - if (newConf.find("bandwidth") != newConf.end()) - { - allPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]); - } - else - { - allPassCoEffs(newConf["freq"], newConf["q"]); - } - break; + if (newConf.find("bandwidth") != newConf.end()) { + allPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]); + } else { + allPassCoEffs(newConf["freq"], newConf["q"]); + } + break; case Type::AllpassFO: - allPassFOCoEffs(newConf["freq"]); - break; - } + allPassFOCoEffs(newConf["freq"]); + break; + } } // coefficients for a high pass biquad filter -void Biquad::highPassCoEffs(float f, float q) -{ - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s / (2 * q); +void Biquad::highPassCoEffs(float f, float q) { + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s / (2 * q); - float b0 = (1 + c) / 2; - float b1 = -(1 + c); - float b2 = b0; - float a0 = 1 + alpha; - float a1 = -2 * c; - float a2 = 1 - alpha; + float b0 = (1 + c) / 2; + float b1 = -(1 + c); + float b2 = b0; + float a0 = 1 + alpha; + float a1 = -2 * c; + float a2 = 1 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } // coefficients for a high pass first order biquad filter -void Biquad::highPassFOCoEffs(float f) -{ - float w0 = 2 * M_PI * f / this->sampleRate; - float k = tanf(w0 / 2.0); +void Biquad::highPassFOCoEffs(float f) { + float w0 = 2 * M_PI * f / this->sampleRate; + float k = tanf(w0 / 2.0); - float alpha = 1.0 + k; + float alpha = 1.0 + k; - float b0 = 1.0 / alpha; - float b1 = -1.0 / alpha; - float b2 = 0.0; - float a0 = 1.0; - float a1 = -(1.0 - k) / alpha; - float a2 = 0.0; + float b0 = 1.0 / alpha; + float b1 = -1.0 / alpha; + float b2 = 0.0; + float a0 = 1.0; + float a1 = -(1.0 - k) / alpha; + float a2 = 0.0; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } // coefficients for a low pass biquad filter -void Biquad::lowPassCoEffs(float f, float q) -{ - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s / (2 * q); +void Biquad::lowPassCoEffs(float f, float q) { + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s / (2 * q); - float b0 = (1 - c) / 2; - float b1 = 1 - c; - float b2 = b0; - float a0 = 1 + alpha; - float a1 = -2 * c; - float a2 = 1 - alpha; + float b0 = (1 - c) / 2; + float b1 = 1 - c; + float b2 = b0; + float a0 = 1 + alpha; + float a1 = -2 * c; + float a2 = 1 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } // coefficients for a low pass first order biquad filter -void Biquad::lowPassFOCoEffs(float f) -{ - float w0 = 2 * M_PI * f / this->sampleRate; - float k = tanf(w0 / 2.0); +void Biquad::lowPassFOCoEffs(float f) { + float w0 = 2 * M_PI * f / this->sampleRate; + float k = tanf(w0 / 2.0); - float alpha = 1.0 + k; + float alpha = 1.0 + k; - float b0 = k / alpha; - float b1 = k / alpha; - float b2 = 0.0; - float a0 = 1.0; - float a1 = -(1.0 - k) / alpha; - float a2 = 0.0; + float b0 = k / alpha; + float b1 = k / alpha; + float b2 = 0.0; + float a0 = 1.0; + float a1 = -(1.0 - k) / alpha; + float a2 = 0.0; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } // coefficients for a peak biquad filter -void Biquad::peakCoEffs(float f, float gain, float q) -{ - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s / (2 * q); +void Biquad::peakCoEffs(float f, float gain, float q) { + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s / (2 * q); - float ampl = std::pow(10.0f, gain / 40.0f); - float b0 = 1.0 + (alpha * ampl); - float b1 = -2.0 * c; - float b2 = 1.0 - (alpha * ampl); - float a0 = 1 + (alpha / ampl); - float a1 = -2 * c; - float a2 = 1 - (alpha / ampl); + float ampl = std::pow(10.0f, gain / 40.0f); + float b0 = 1.0 + (alpha * ampl); + float b1 = -2.0 * c; + float b2 = 1.0 - (alpha * ampl); + float a0 = 1 + (alpha / ampl); + float a1 = -2 * c; + float a2 = 1 - (alpha / ampl); - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } -void Biquad::peakCoEffsBandwidth(float f, float gain, float bandwidth) -{ - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); +void Biquad::peakCoEffsBandwidth(float f, float gain, float bandwidth) { + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); - float ampl = std::pow(10.0f, gain / 40.0f); - float b0 = 1.0 + (alpha * ampl); - float b1 = -2.0 * c; - float b2 = 1.0 - (alpha * ampl); - float a0 = 1 + (alpha / ampl); - float a1 = -2 * c; - float a2 = 1 - (alpha / ampl); + float ampl = std::pow(10.0f, gain / 40.0f); + float b0 = 1.0 + (alpha * ampl); + float b1 = -2.0 * c; + float b2 = 1.0 - (alpha * ampl); + float a0 = 1 + (alpha / ampl); + float a1 = -2 * c; + float a2 = 1 - (alpha / ampl); - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } -void Biquad::highShelfCoEffs(float f, float gain, float q) -{ - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s / (2 * q); - float beta = s * sqrtf(A) / q; - float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta); - float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c); - float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta); - float a0 = (A + 1.0) - (A - 1.0) * c + beta; - float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c); - float a2 = (A + 1.0) - (A - 1.0) * c - beta; +void Biquad::highShelfCoEffs(float f, float gain, float q) { + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s / (2 * q); + float beta = s * sqrtf(A) / q; + float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta); + float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c); + float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta); + float a0 = (A + 1.0) - (A - 1.0) * c + beta; + float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c); + float a2 = (A + 1.0) - (A - 1.0) * c - beta; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } -void Biquad::highShelfCoEffsSlope(float f, float gain, float slope) -{ - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = - s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0); - float beta = 2.0 * sqrtf(A) * alpha; - float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta); - float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c); - float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta); - float a0 = (A + 1.0) - (A - 1.0) * c + beta; - float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c); - float a2 = (A + 1.0) - (A - 1.0) * c - beta; +void Biquad::highShelfCoEffsSlope(float f, float gain, float slope) { + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = + s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0); + float beta = 2.0 * sqrtf(A) * alpha; + float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta); + float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c); + float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta); + float a0 = (A + 1.0) - (A - 1.0) * c + beta; + float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c); + float a2 = (A + 1.0) - (A - 1.0) * c - beta; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } -void Biquad::highShelfFOCoEffs(float f, float gain) -{ - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float tn = tanf(w0 / 2.0); +void Biquad::highShelfFOCoEffs(float f, float gain) { + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float tn = tanf(w0 / 2.0); - float b0 = A * tn + std::pow(A, 2); - float b1 = A * tn - std::pow(A, 2); - float b2 = 0.0; - float a0 = A * tn + 1.0; - float a1 = A * tn - 1.0; - float a2 = 0.0; + float b0 = A * tn + std::pow(A, 2); + float b1 = A * tn - std::pow(A, 2); + float b2 = 0.0; + float a0 = A * tn + 1.0; + float a1 = A * tn - 1.0; + float a2 = 0.0; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::lowShelfCoEffs(float f, float gain, float q) { - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float beta = s * sqrtf(A) / q; + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float beta = s * sqrtf(A) / q; - float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta); - float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c); - float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta); - float a0 = (A + 1.0) + (A - 1.0) * c + beta; - float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c); - float a2 = (A + 1.0) + (A - 1.0) * c - beta; + float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta); + float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c); + float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta); + float a0 = (A + 1.0) + (A - 1.0) * c + beta; + float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c); + float a2 = (A + 1.0) + (A - 1.0) * c - beta; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::lowShelfCoEffsSlope(float f, float gain, float slope) { - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = - s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0); - float beta = 2.0 * sqrtf(A) * alpha; + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = + s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0); + float beta = 2.0 * sqrtf(A) * alpha; - float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta); - float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c); - float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta); - float a0 = (A + 1.0) + (A - 1.0) * c + beta; - float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c); - float a2 = (A + 1.0) + (A - 1.0) * c - beta; + float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta); + float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c); + float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta); + float a0 = (A + 1.0) + (A - 1.0) * c + beta; + float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c); + float a2 = (A + 1.0) + (A - 1.0) * c - beta; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::lowShelfFOCoEffs(float f, float gain) { - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float tn = tanf(w0 / 2.0); + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float tn = tanf(w0 / 2.0); - float b0 = std::pow(A, 2) * tn + A; - float b1 = std::pow(A, 2) * tn - A; - float b2 = 0.0; - float a0 = tn + A; - float a1 = tn - A; - float a2 = 0.0; + float b0 = std::pow(A, 2) * tn + A; + float b1 = std::pow(A, 2) * tn - A; + float b2 = 0.0; + float a0 = tn + A; + float a1 = tn - A; + float a2 = 0.0; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::notchCoEffs(float f, float gain, float q) { - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s / (2.0 * q); + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s / (2.0 * q); - float b0 = 1.0; - float b1 = -2.0 * c; - float b2 = 1.0; - float a0 = 1.0 + alpha; - float a1 = -2.0 * c; - float a2 = 1.0 - alpha; + float b0 = 1.0; + float b1 = -2.0 * c; + float b2 = 1.0; + float a0 = 1.0 + alpha; + float a1 = -2.0 * c; + float a2 = 1.0 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::notchCoEffsBandwidth(float f, float gain, float bandwidth) { - float A = std::pow(10.0f, gain / 40.0f); - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); + float A = std::pow(10.0f, gain / 40.0f); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); - float b0 = 1.0; - float b1 = -2.0 * c; - float b2 = 1.0; - float a0 = 1.0 + alpha; - float a1 = -2.0 * c; - float a2 = 1.0 - alpha; + float b0 = 1.0; + float b1 = -2.0 * c; + float b2 = 1.0; + float a0 = 1.0 + alpha; + float a1 = -2.0 * c; + float a2 = 1.0 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::bandPassCoEffs(float f, float q) { - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s / (2.0 * q); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s / (2.0 * q); - float b0 = alpha; - float b1 = 0.0; - float b2 = -alpha; - float a0 = 1.0 + alpha; - float a1 = -2.0 * c; - float a2 = 1.0 - alpha; + float b0 = alpha; + float b1 = 0.0; + float b2 = -alpha; + float a0 = 1.0 + alpha; + float a1 = -2.0 * c; + float a2 = 1.0 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::bandPassCoEffsBandwidth(float f, float bandwidth) { - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); - float b0 = alpha; - float b1 = 0.0; - float b2 = -alpha; - float a0 = 1.0 + alpha; - float a1 = -2.0 * c; - float a2 = 1.0 - alpha; + float b0 = alpha; + float b1 = 0.0; + float b2 = -alpha; + float a0 = 1.0 + alpha; + float a1 = -2.0 * c; + float a2 = 1.0 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::allPassCoEffs(float f, float q) { - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s / (2.0 * q); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s / (2.0 * q); - float b0 = 1.0 - alpha; - float b1 = -2.0 * c; - float b2 = 1.0 + alpha; - float a0 = 1.0 + alpha; - float a1 = -2.0 * c; - float a2 = 1.0 - alpha; + float b0 = 1.0 - alpha; + float b1 = -2.0 * c; + float b2 = 1.0 + alpha; + float a0 = 1.0 + alpha; + float a1 = -2.0 * c; + float a2 = 1.0 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::allPassCoEffsBandwidth(float f, float bandwidth) { - float w0 = 2 * M_PI * f / this->sampleRate; - float c = cosf(w0); - float s = sinf(w0); - float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); + float w0 = 2 * M_PI * f / this->sampleRate; + float c = cosf(w0); + float s = sinf(w0); + float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s); - float b0 = 1.0 - alpha; - float b1 = -2.0 * c; - float b2 = 1.0 + alpha; - float a0 = 1.0 + alpha; - float a1 = -2.0 * c; - float a2 = 1.0 - alpha; + float b0 = 1.0 - alpha; + float b1 = -2.0 * c; + float b2 = 1.0 + alpha; + float a0 = 1.0 + alpha; + float a1 = -2.0 * c; + float a2 = 1.0 - alpha; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } void Biquad::allPassFOCoEffs(float f) { - float w0 = 2 * M_PI * f / this->sampleRate; - float tn = tanf(w0 / 2.0); + float w0 = 2 * M_PI * f / this->sampleRate; + float tn = tanf(w0 / 2.0); - float alpha = (tn + 1.0) / (tn - 1.0); + float alpha = (tn + 1.0) / (tn - 1.0); - float b0 = 1.0; - float b1 = alpha; - float b2 = 0.0; - float a0 = alpha; - float a1 = 1.0; - float a2 = 0.0; + float b0 = 1.0; + float b1 = alpha; + float b2 = 0.0; + float a0 = alpha; + float a1 = 1.0; + float a2 = 0.0; - this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); + this->normalizeCoEffs(a0, a1, a2, b0, b1, b2); } -void Biquad::normalizeCoEffs(float a0, float a1, float a2, float b0, float b1, float b2) -{ - coeffs[0] = b0 / a0; - coeffs[1] = b1 / a0; - coeffs[2] = b2 / a0; - coeffs[3] = a1 / a0; - coeffs[4] = a2 / a0; +void Biquad::normalizeCoEffs(float a0, float a1, float a2, float b0, float b1, + float b2) { + coeffs[0] = b0 / a0; + coeffs[1] = b1 / a0; + coeffs[2] = b2 / a0; + coeffs[3] = a1 / a0; + coeffs[4] = a2 / a0; } -std::unique_ptr Biquad::process(std::unique_ptr stream) -{ - std::scoped_lock lock(accessMutex); +std::unique_ptr Biquad::process( + std::unique_ptr stream) { + std::scoped_lock lock(accessMutex); - auto input = stream->data[this->channel]; - auto numSamples = stream->numSamples; + auto input = stream->data[this->channel]; + auto numSamples = stream->numSamples; #ifdef ESP_PLATFORM - dsps_biquad_f32_ae32(input, input, numSamples, coeffs, w); + dsps_biquad_f32_ae32(input, input, numSamples, coeffs, w); #else - // Apply the set coefficients - for (int i = 0; i < numSamples; i++) - { - float d0 = input[i] - coeffs[3] * w[0] - coeffs[4] * w[1]; - input[i] = coeffs[0] * d0 + coeffs[1] * w[0] + coeffs[2] * w[1]; - w[1] = w[0]; - w[0] = d0; - } + // Apply the set coefficients + for (int i = 0; i < numSamples; i++) { + float d0 = input[i] - coeffs[3] * w[0] - coeffs[4] * w[1]; + input[i] = coeffs[0] * d0 + coeffs[1] * w[0] + coeffs[2] * w[1]; + w[1] = w[0]; + w[0] = d0; + } #endif - return stream; + return stream; }; diff --git a/components/spotify/cspot/bell/main/audio-dsp/BiquadCombo.cpp b/components/spotify/cspot/bell/main/audio-dsp/BiquadCombo.cpp index 8c962700..90ed50fb 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/BiquadCombo.cpp +++ b/components/spotify/cspot/bell/main/audio-dsp/BiquadCombo.cpp @@ -1,109 +1,89 @@ #include "BiquadCombo.h" +#include // for printf +#include // for sinf, M_PI +#include // for move + using namespace bell; -BiquadCombo::BiquadCombo() -{ +BiquadCombo::BiquadCombo() {} + +void BiquadCombo::sampleRateChanged(uint32_t sampleRate) { + for (auto& biquad : biquads) { + biquad->sampleRateChanged(sampleRate); + } } -void BiquadCombo::sampleRateChanged(uint32_t sampleRate) -{ - for (auto &biquad : biquads) - { - biquad->sampleRateChanged(sampleRate); - } +std::vector BiquadCombo::calculateBWQ(int order) { + + std::vector qValues; + for (int n = 0; n < order / 2; n++) { + float q = 1.0f / (2.0f * sinf(M_PI / order * (((float)n) + 0.5))); + qValues.push_back(q); + } + + if (order % 2 > 0) { + qValues.push_back(-1.0); + } + + printf("%d\n", qValues.size()); + + return qValues; } -std::vector BiquadCombo::calculateBWQ(int order) -{ +std::vector BiquadCombo::calculateLRQ(int order) { + auto qValues = calculateBWQ(order / 2); - std::vector qValues; - for (int n = 0; n < order / 2; n++) - { - float q = 1.0f / (2.0f * sinf(M_PI / order * (((float)n) + 0.5))); - qValues.push_back(q); - } + if (order % 4 > 0) { + qValues.pop_back(); + qValues.insert(qValues.end(), qValues.begin(), qValues.end()); + qValues.push_back(0.5); + } else { + qValues.insert(qValues.end(), qValues.begin(), qValues.end()); + } - if (order % 2 > 0) - { - qValues.push_back(-1.0); - } - - printf("%d\n", qValues.size()); - - return qValues; + return qValues; } -std::vector BiquadCombo::calculateLRQ(int order) -{ - auto qValues = calculateBWQ(order / 2); - - if (order % 4 > 0) - { - qValues.pop_back(); - qValues.insert(qValues.end(), qValues.begin(), qValues.end()); - qValues.push_back(0.5); - } - else - { - qValues.insert(qValues.end(), qValues.begin(), qValues.end()); - } - - return qValues; +void BiquadCombo::butterworth(float freq, int order, FilterType type) { + std::vector qValues = calculateBWQ(order); + for (auto& q : qValues) {} } -void BiquadCombo::butterworth(float freq, int order, FilterType type) -{ - std::vector qValues = calculateBWQ(order); - for (auto &q : qValues) - { +void BiquadCombo::linkwitzRiley(float freq, int order, FilterType type) { + std::vector qValues = calculateLRQ(order); + for (auto& q : qValues) { + auto filter = std::make_unique(); + filter->channel = channel; + + auto config = std::map(); + config["freq"] = freq; + config["q"] = q; + + if (q >= 0.0) { + if (type == FilterType::Highpass) { + filter->configure(Biquad::Type::Highpass, config); + } else { + filter->configure(Biquad::Type::Lowpass, config); + } + } else { + if (type == FilterType::Highpass) { + filter->configure(Biquad::Type::HighpassFO, config); + } else { + filter->configure(Biquad::Type::LowpassFO, config); + } } + + this->biquads.push_back(std::move(filter)); + } } -void BiquadCombo::linkwitzRiley(float freq, int order, FilterType type) -{ - std::vector qValues = calculateLRQ(order); - for (auto &q : qValues) - { - auto filter = std::make_unique(); - filter->channel = channel; +std::unique_ptr BiquadCombo::process( + std::unique_ptr data) { + std::scoped_lock lock(this->accessMutex); + for (auto& transform : this->biquads) { + data = transform->process(std::move(data)); + } - auto config = std::map(); - config["freq"] = freq; - config["q"] = q; - - if (q >= 0.0) - { - if (type == FilterType::Highpass) - { - filter->configure(Biquad::Type::Highpass, config); - } - else - { - filter->configure(Biquad::Type::Lowpass, config); - } - } - else - { - if (type == FilterType::Highpass) - { - filter->configure(Biquad::Type::HighpassFO, config); - } - else - { - filter->configure(Biquad::Type::LowpassFO, config); - } - } - - this->biquads.push_back(std::move(filter)); - } -} - -std::unique_ptr BiquadCombo::process(std::unique_ptr data) { - std::scoped_lock lock(this->accessMutex); - for (auto &transform : this->biquads) { - data = transform->process(std::move(data)); - } - - return data; + return data; } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/Compressor.cpp b/components/spotify/cspot/bell/main/audio-dsp/Compressor.cpp index 95194fbf..aa8bb48b 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/Compressor.cpp +++ b/components/spotify/cspot/bell/main/audio-dsp/Compressor.cpp @@ -1,5 +1,7 @@ #include "Compressor.h" +#include // for abs + using namespace bell; float log2f_approx(float X) { @@ -19,11 +21,11 @@ float log2f_approx(float X) { Compressor::Compressor() {} -void Compressor::sumChannels(std::unique_ptr &data) { +void Compressor::sumChannels(std::unique_ptr& data) { tmp.resize(data->numSamples); for (int i = 0; i < data->numSamples; i++) { float sum = 0.0f; - for (auto &channel : channels) { + for (auto& channel : channels) { sum += data->data[channel][i]; } tmp[i] = sum; @@ -31,7 +33,7 @@ void Compressor::sumChannels(std::unique_ptr &data) { } void Compressor::calLoudness() { - for (auto &value : tmp) { + for (auto& value : tmp) { value = 20 * log10f_fast(std::abs(value) + 1.0e-9f); if (value >= lastLoudness) { value = attack * lastLoudness + (1.0 - attack) * value; @@ -44,7 +46,7 @@ void Compressor::calLoudness() { } void Compressor::calGain() { - for (auto &value : tmp) { + for (auto& value : tmp) { if (value > threshold) { value = -(value - threshold) * (factor - 1.0) / factor; } else { @@ -58,9 +60,9 @@ void Compressor::calGain() { } } -void Compressor::applyGain(std::unique_ptr &data) { +void Compressor::applyGain(std::unique_ptr& data) { for (int i = 0; i < data->numSamples; i++) { - for (auto &channel : channels) { + for (auto& channel : channels) { data->data[channel][i] *= tmp[i]; } } diff --git a/components/spotify/cspot/bell/main/audio-dsp/Gain.cpp b/components/spotify/cspot/bell/main/audio-dsp/Gain.cpp index 9775758a..a2b8fe23 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/Gain.cpp +++ b/components/spotify/cspot/bell/main/audio-dsp/Gain.cpp @@ -1,31 +1,29 @@ #include "Gain.h" +#include // for pow +#include // for string + using namespace bell; -Gain::Gain() : AudioTransform() -{ - this->gainFactor = 1.0f; - this->filterType = "gain"; +Gain::Gain() : AudioTransform() { + this->gainFactor = 1.0f; + this->filterType = "gain"; } -void Gain::configure(std::vector channels, float gainDB) -{ - this->channels = channels; - this->gainDb = gainDB; - this->gainFactor = std::pow(10.0f, gainDB / 20.0f); +void Gain::configure(std::vector channels, float gainDB) { + this->channels = channels; + this->gainDb = gainDB; + this->gainFactor = std::pow(10.0f, gainDB / 20.0f); } -std::unique_ptr Gain::process(std::unique_ptr data) -{ - std::scoped_lock lock(this->accessMutex); - for (int i = 0; i < data->numSamples; i++) - { - // Apply gain to all channels - for (auto &channel : channels) - { - data->data[channel][i] *= gainFactor; - } +std::unique_ptr Gain::process(std::unique_ptr data) { + std::scoped_lock lock(this->accessMutex); + for (int i = 0; i < data->numSamples; i++) { + // Apply gain to all channels + for (auto& channel : channels) { + data->data[channel][i] *= gainFactor; } + } - return data; + return data; } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/AudioMixer.h b/components/spotify/cspot/bell/main/audio-dsp/include/AudioMixer.h index 979b878c..04b86b09 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/AudioMixer.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/AudioMixer.h @@ -1,89 +1,80 @@ #pragma once -#include -#include -#include +#include // for cJSON_GetObjectItem, cJSON, cJSON_IsArray +#include // for NULL +#include // for find +#include // for uint8_t +#include // for unique_ptr +#include // for invalid_argument +#include // for vector -#include "AudioTransform.h" +#include "AudioTransform.h" // for AudioTransform +#include "StreamInfo.h" // for StreamInfo -namespace bell -{ - class AudioMixer : public bell::AudioTransform - { - public: - enum DownmixMode - { - DEFAULT - }; +namespace bell { +class AudioMixer : public bell::AudioTransform { + public: + enum DownmixMode { DEFAULT }; - struct MixerConfig - { - std::vector source; - int destination; - }; + struct MixerConfig { + std::vector source; + int destination; + }; - AudioMixer(); - ~AudioMixer(){}; - // Amount of channels in the input - int from; + AudioMixer(); + ~AudioMixer(){}; + // Amount of channels in the input + int from; - // Amount of channels in the output - int to; + // Amount of channels in the output + int to; - // Configuration of each channels in the mixer - std::vector mixerConfig; + // Configuration of each channels in the mixer + std::vector mixerConfig; - std::unique_ptr process(std::unique_ptr data) override; + std::unique_ptr process( + std::unique_ptr data) override; - void reconfigure() override - { + void reconfigure() override {} + + void fromJSON(cJSON* json) { + cJSON* mappedChannels = cJSON_GetObjectItem(json, "mapped_channels"); + + if (mappedChannels == NULL || !cJSON_IsArray(mappedChannels)) { + throw std::invalid_argument("Mixer configuration invalid"); + } + + this->mixerConfig = std::vector(); + + cJSON* iterator = NULL; + cJSON_ArrayForEach(iterator, mappedChannels) { + std::vector sources(0); + cJSON* iteratorNested = NULL; + cJSON_ArrayForEach(iteratorNested, + cJSON_GetObjectItem(iterator, "source")) { + sources.push_back(iteratorNested->valueint); + } + + int destination = cJSON_GetObjectItem(iterator, "destination")->valueint; + + this->mixerConfig.push_back( + MixerConfig{.source = sources, .destination = destination}); + } + + std::vector sources(0); + + for (auto& config : mixerConfig) { + + for (auto& source : config.source) { + if (std::find(sources.begin(), sources.end(), source) == + sources.end()) { + sources.push_back(source); } + } + } - void fromJSON(cJSON *json) - { - cJSON *mappedChannels = cJSON_GetObjectItem(json, "mapped_channels"); - - if (mappedChannels == NULL || !cJSON_IsArray(mappedChannels)) - { - throw std::invalid_argument("Mixer configuration invalid"); - } - - this->mixerConfig = std::vector(); - - cJSON *iterator = NULL; - cJSON_ArrayForEach(iterator, mappedChannels) - { - std::vector sources(0); - cJSON *iteratorNested = NULL; - cJSON_ArrayForEach(iteratorNested, cJSON_GetObjectItem(iterator, "source")) - { - sources.push_back(iteratorNested->valueint); - } - - int destination = cJSON_GetObjectItem(iterator, "destination")->valueint; - - this->mixerConfig.push_back(MixerConfig{ - .source = sources, - .destination = destination - }); - } - - std::vector sources(0); - - for (auto &config : mixerConfig) - { - - for (auto &source : config.source) - { - if (std::find(sources.begin(), sources.end(), source) == sources.end()) - { - sources.push_back(source); - } - } - } - - this->from = sources.size(); - this->to = mixerConfig.size(); - } - }; -} \ No newline at end of file + this->from = sources.size(); + this->to = mixerConfig.size(); + } +}; +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/AudioPipeline.h b/components/spotify/cspot/bell/main/audio-dsp/include/AudioPipeline.h index 5f1b0559..211d5b57 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/AudioPipeline.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/AudioPipeline.h @@ -1,28 +1,29 @@ #pragma once -#include "AudioTransform.h" -#include "StreamInfo.h" -#include -#include "Gain.h" -#include +#include // for shared_ptr, unique_ptr +#include // for mutex +#include // for vector -namespace bell -{ - class AudioPipeline - { - private: - std::shared_ptr headroomGainTransform; +#include "StreamInfo.h" // for StreamInfo - public: - AudioPipeline(); - ~AudioPipeline(){}; +namespace bell { +class AudioTransform; +class Gain; - std::mutex accessMutex; - std::vector> transforms; +class AudioPipeline { + private: + std::shared_ptr headroomGainTransform; - void recalculateHeadroom(); - void addTransform(std::shared_ptr transform); - void volumeUpdated(int volume); - std::unique_ptr process(std::unique_ptr data); - }; -}; // namespace bell \ No newline at end of file + public: + AudioPipeline(); + ~AudioPipeline(){}; + + std::mutex accessMutex; + std::vector> transforms; + + void recalculateHeadroom(); + void addTransform(std::shared_ptr transform); + void volumeUpdated(int volume); + std::unique_ptr process(std::unique_ptr data); +}; +}; // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/AudioTransform.h b/components/spotify/cspot/bell/main/audio-dsp/include/AudioTransform.h index 1845aca4..697a0e10 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/AudioTransform.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/AudioTransform.h @@ -1,29 +1,28 @@ #pragma once #include -#include #include +#include #include "StreamInfo.h" #include "TransformConfig.h" -namespace bell -{ - class AudioTransform - { - protected: - std::mutex accessMutex; +namespace bell { +class AudioTransform { + protected: + std::mutex accessMutex; - public: - virtual std::unique_ptr process(std::unique_ptr data) = 0; - virtual void sampleRateChanged(uint32_t sampleRate){}; - virtual float calculateHeadroom() { return 0; }; + public: + virtual std::unique_ptr process( + std::unique_ptr data) = 0; + virtual void sampleRateChanged(uint32_t sampleRate){}; + virtual float calculateHeadroom() { return 0; }; - virtual void reconfigure() {}; + virtual void reconfigure(){}; - std::string filterType; - std::unique_ptr config; + std::string filterType; + std::unique_ptr config; - AudioTransform() = default; - virtual ~AudioTransform() = default; - }; -}; \ No newline at end of file + AudioTransform() = default; + virtual ~AudioTransform() = default; +}; +}; // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/BellDSP.h b/components/spotify/cspot/bell/main/audio-dsp/include/BellDSP.h index 5589731e..8e618710 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/BellDSP.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/BellDSP.h @@ -1,34 +1,43 @@ #pragma once -#include -#include -#include -#include "AudioPipeline.h" -#include "CentralAudioBuffer.h" +#include // for size_t +#include // for uint32_t, uint8_t +#include // for function +#include // for shared_ptr, unique_ptr +#include // for mutex +#include // for vector + +#include "StreamInfo.h" // for BitWidth namespace bell { +class AudioPipeline; +class CentralAudioBuffer; + #define MAX_INT16 32767 class BellDSP { public: BellDSP(std::shared_ptr centralAudioBuffer); - ~BellDSP() {}; + ~BellDSP(){}; class AudioEffect { public: AudioEffect() = default; ~AudioEffect() = default; size_t duration; - virtual void apply(float* sampleData, size_t samples, size_t relativePosition) = 0; + virtual void apply(float* sampleData, size_t samples, + size_t relativePosition) = 0; }; - class FadeEffect: public AudioEffect { - private: + class FadeEffect : public AudioEffect { + private: std::function onFinish; bool isFadeIn; - public: - FadeEffect(size_t duration, bool isFadeIn, std::function onFinish = nullptr); - ~FadeEffect() {}; + + public: + FadeEffect(size_t duration, bool isFadeIn, + std::function onFinish = nullptr); + ~FadeEffect(){}; void apply(float* sampleData, size_t samples, size_t relativePosition); }; @@ -38,8 +47,8 @@ class BellDSP { std::shared_ptr getActivePipeline(); - size_t process(uint8_t* data, size_t bytes, int channels, - uint32_t sampleRate, BitWidth bitWidth); + size_t process(uint8_t* data, size_t bytes, int channels, uint32_t sampleRate, + BitWidth bitWidth); private: std::shared_ptr activePipeline; @@ -48,7 +57,6 @@ class BellDSP { std::vector dataLeft = std::vector(1024); std::vector dataRight = std::vector(1024); - std::unique_ptr underflowEffect = nullptr; std::unique_ptr startEffect = nullptr; std::unique_ptr instantEffect = nullptr; diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/Biquad.h b/components/spotify/cspot/bell/main/audio-dsp/include/Biquad.h index 2c2ce662..01195a3c 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/Biquad.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/Biquad.h @@ -1,158 +1,158 @@ #pragma once -#include -#include -#include -#include +#include // for uint32_t +#include // for map +#include // for unique_ptr, allocator +#include // for scoped_lock +#include // for invalid_argument +#include // for string, operator<, hash, operator== +#include // for operator!=, unordered_map, __hash_map_c... +#include // for pair +#include // for vector -#include "AudioTransform.h" -extern "C" int dsps_biquad_f32_ae32(const float *input, float *output, int len, float *coef, float *w); +#include "AudioTransform.h" // for AudioTransform +#include "StreamInfo.h" // for StreamInfo +#include "TransformConfig.h" // for TransformConfig -namespace bell -{ - class Biquad : public bell::AudioTransform - { - public: - Biquad(); - ~Biquad(){}; +extern "C" int dsps_biquad_f32_ae32(const float* input, float* output, int len, + float* coef, float* w); - enum class Type - { - Free, - Highpass, - Lowpass, - HighpassFO, - LowpassFO, +namespace bell { +class Biquad : public bell::AudioTransform { + public: + Biquad(); + ~Biquad(){}; - Peaking, - Highshelf, - HighshelfFO, - Lowshelf, - LowshelfFO, - Notch, - Bandpass, - Allpass, - AllpassFO - }; + enum class Type { + Free, + Highpass, + Lowpass, + HighpassFO, + LowpassFO, - std::map currentConfig; + Peaking, + Highshelf, + HighshelfFO, + Lowshelf, + LowshelfFO, + Notch, + Bandpass, + Allpass, + AllpassFO + }; - std::unordered_map const strMapType = { - {"free", Type::Free}, - {"highpass", Type::Highpass}, - {"lowpass", Type::Lowpass}, - {"highpass_fo", Type::HighpassFO}, - {"lowpass_fo", Type::LowpassFO}, - {"peaking", Type::Peaking}, - {"highshelf", Type::Highshelf}, - {"highshelf_fo", Type::HighpassFO}, - {"lowshelf", Type::Lowshelf}, - {"lowshelf_fo", Type::LowpassFO}, - {"notch", Type::Notch}, - {"bandpass", Type::Bandpass}, - {"allpass", Type::Allpass}, - {"allpass_fo", Type::AllpassFO}, - }; + std::map currentConfig; - float freq, q, gain; - int channel; - Biquad::Type type; + std::unordered_map const strMapType = { + {"free", Type::Free}, + {"highpass", Type::Highpass}, + {"lowpass", Type::Lowpass}, + {"highpass_fo", Type::HighpassFO}, + {"lowpass_fo", Type::LowpassFO}, + {"peaking", Type::Peaking}, + {"highshelf", Type::Highshelf}, + {"highshelf_fo", Type::HighpassFO}, + {"lowshelf", Type::Lowshelf}, + {"lowshelf_fo", Type::LowpassFO}, + {"notch", Type::Notch}, + {"bandpass", Type::Bandpass}, + {"allpass", Type::Allpass}, + {"allpass_fo", Type::AllpassFO}, + }; - std::unique_ptr process(std::unique_ptr data) override; + float freq, q, gain; + int channel; + Biquad::Type type; - void configure(Type type, std::map &config); + std::unique_ptr process( + std::unique_ptr data) override; - void sampleRateChanged(uint32_t sampleRate) override; + void configure(Type type, std::map& config); - void reconfigure() override - { - std::scoped_lock lock(this->accessMutex); - std::map biquadConfig; - this->channel = config->getChannels()[0]; + void sampleRateChanged(uint32_t sampleRate) override; - float invalid = -0x7C; + void reconfigure() override { + std::scoped_lock lock(this->accessMutex); + std::map biquadConfig; + this->channel = config->getChannels()[0]; - auto type = config->getString("biquad_type"); - float bandwidth = config->getFloat("bandwidth", false, invalid); - float slope = config->getFloat("slope", false, invalid); - float gain = config->getFloat("gain", false, invalid); - float frequency = config->getFloat("frequency", false, invalid); - float q = config->getFloat("q", false, invalid); + float invalid = -0x7C; - if (currentConfig["bandwidth"] == bandwidth && - currentConfig["slope"] == slope && - currentConfig["gain"] == gain && - currentConfig["frequency"] == frequency && - currentConfig["q"] == q) - { - return; - } + auto type = config->getString("biquad_type"); + float bandwidth = config->getFloat("bandwidth", false, invalid); + float slope = config->getFloat("slope", false, invalid); + float gain = config->getFloat("gain", false, invalid); + float frequency = config->getFloat("frequency", false, invalid); + float q = config->getFloat("q", false, invalid); - if (bandwidth != invalid) - biquadConfig["bandwidth"] = bandwidth; - if (slope != invalid) - biquadConfig["slope"] = slope; - if (gain != invalid) - biquadConfig["gain"] = gain; - if (frequency != invalid) - biquadConfig["freq"] = frequency; - if (q != invalid) - biquadConfig["q"] = q; + if (currentConfig["bandwidth"] == bandwidth && + currentConfig["slope"] == slope && currentConfig["gain"] == gain && + currentConfig["frequency"] == frequency && currentConfig["q"] == q) { + return; + } - if (type == "free") - { - biquadConfig["a1"] = config->getFloat("a1"); - biquadConfig["a2"] = config->getFloat("a2"); - biquadConfig["b0"] = config->getFloat("b0"); - biquadConfig["b1"] = config->getFloat("b1"); - biquadConfig["b2"] = config->getFloat("b2"); - } + if (bandwidth != invalid) + biquadConfig["bandwidth"] = bandwidth; + if (slope != invalid) + biquadConfig["slope"] = slope; + if (gain != invalid) + biquadConfig["gain"] = gain; + if (frequency != invalid) + biquadConfig["freq"] = frequency; + if (q != invalid) + biquadConfig["q"] = q; - auto typeElement = strMapType.find(type); - if (typeElement != strMapType.end()) - { - this->configure(typeElement->second, biquadConfig); - } - else - { - throw std::invalid_argument("No biquad of type " + type); - } - } + if (type == "free") { + biquadConfig["a1"] = config->getFloat("a1"); + biquadConfig["a2"] = config->getFloat("a2"); + biquadConfig["b0"] = config->getFloat("b0"); + biquadConfig["b1"] = config->getFloat("b1"); + biquadConfig["b2"] = config->getFloat("b2"); + } - private: - float coeffs[5]; - float w[2] = {1.0, 1.0}; + auto typeElement = strMapType.find(type); + if (typeElement != strMapType.end()) { + this->configure(typeElement->second, biquadConfig); + } else { + throw std::invalid_argument("No biquad of type " + type); + } + } - float sampleRate = 44100; + private: + float coeffs[5]; + float w[2] = {1.0, 1.0}; - // Generator methods for different filter types - void highPassCoEffs(float f, float q); - void highPassFOCoEffs(float f); - void lowPassCoEffs(float f, float q); - void lowPassFOCoEffs(float f); + float sampleRate = 44100; - void peakCoEffs(float f, float gain, float q); - void peakCoEffsBandwidth(float f, float gain, float bandwidth); + // Generator methods for different filter types + void highPassCoEffs(float f, float q); + void highPassFOCoEffs(float f); + void lowPassCoEffs(float f, float q); + void lowPassFOCoEffs(float f); - void highShelfCoEffs(float f, float gain, float q); - void highShelfCoEffsSlope(float f, float gain, float slope); - void highShelfFOCoEffs(float f, float gain); + void peakCoEffs(float f, float gain, float q); + void peakCoEffsBandwidth(float f, float gain, float bandwidth); - void lowShelfCoEffs(float f, float gain, float q); - void lowShelfCoEffsSlope(float f, float gain, float slope); - void lowShelfFOCoEffs(float f, float gain); + void highShelfCoEffs(float f, float gain, float q); + void highShelfCoEffsSlope(float f, float gain, float slope); + void highShelfFOCoEffs(float f, float gain); - void notchCoEffs(float f, float gain, float q); - void notchCoEffsBandwidth(float f, float gain, float bandwidth); + void lowShelfCoEffs(float f, float gain, float q); + void lowShelfCoEffsSlope(float f, float gain, float slope); + void lowShelfFOCoEffs(float f, float gain); - void bandPassCoEffs(float f, float q); - void bandPassCoEffsBandwidth(float f, float bandwidth); + void notchCoEffs(float f, float gain, float q); + void notchCoEffsBandwidth(float f, float gain, float bandwidth); - void allPassCoEffs(float f, float q); - void allPassCoEffsBandwidth(float f, float bandwidth); - void allPassFOCoEffs(float f); + void bandPassCoEffs(float f, float q); + void bandPassCoEffsBandwidth(float f, float bandwidth); - void normalizeCoEffs(float a0, float a1, float a2, float b0, float b1, float b2); - }; + void allPassCoEffs(float f, float q); + void allPassCoEffsBandwidth(float f, float bandwidth); + void allPassFOCoEffs(float f); -} \ No newline at end of file + void normalizeCoEffs(float a0, float a1, float a2, float b0, float b1, + float b2); +}; + +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/BiquadCombo.h b/components/spotify/cspot/bell/main/audio-dsp/include/BiquadCombo.h index 66a75f38..bc7234dd 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/BiquadCombo.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/BiquadCombo.h @@ -1,85 +1,71 @@ #pragma once -#include -#include -#include -#include -#include +#include // for uint32_t +#include // for map +#include // for unique_ptr, allocator +#include // for scoped_lock +#include // for invalid_argument +#include // for string, operator==, char_traits, basic_... +#include // for vector -#include "Biquad.h" -#include "AudioTransform.h" +#include "AudioTransform.h" // for AudioTransform +#include "Biquad.h" // for Biquad +#include "StreamInfo.h" // for StreamInfo +#include "TransformConfig.h" // for TransformConfig -namespace bell -{ - class BiquadCombo : public bell::AudioTransform - { - private: - std::vector> biquads; +namespace bell { +class BiquadCombo : public bell::AudioTransform { + private: + std::vector> biquads; - // Calculates Q values for Nth order Butterworth / Linkwitz-Riley filters - std::vector calculateBWQ(int order); - std::vector calculateLRQ(int order); + // Calculates Q values for Nth order Butterworth / Linkwitz-Riley filters + std::vector calculateBWQ(int order); + std::vector calculateLRQ(int order); - public: - BiquadCombo(); - ~BiquadCombo(){}; - int channel; + public: + BiquadCombo(); + ~BiquadCombo(){}; + int channel; - std::map paramCache = { - {"order", 0.0f}, - {"frequency", 0.0f} - }; + std::map paramCache = {{"order", 0.0f}, + {"frequency", 0.0f}}; - enum class FilterType - { - Highpass, - Lowpass - }; + enum class FilterType { Highpass, Lowpass }; - void linkwitzRiley(float freq, int order, FilterType type); - void butterworth(float freq, int order, FilterType type); + void linkwitzRiley(float freq, int order, FilterType type); + void butterworth(float freq, int order, FilterType type); - std::unique_ptr process(std::unique_ptr data) override; - void sampleRateChanged(uint32_t sampleRate) override; + std::unique_ptr process( + std::unique_ptr data) override; + void sampleRateChanged(uint32_t sampleRate) override; - void reconfigure() override - { - std::scoped_lock lock(this->accessMutex); + void reconfigure() override { + std::scoped_lock lock(this->accessMutex); - float freq = config->getFloat("frequency"); - int order = config->getInt("order"); + float freq = config->getFloat("frequency"); + int order = config->getInt("order"); - if (paramCache["frequency"] == freq && paramCache["order"] == order) - { - return; - } else { - paramCache["frequency"] = freq; - paramCache["order"] = order; - } + if (paramCache["frequency"] == freq && paramCache["order"] == order) { + return; + } else { + paramCache["frequency"] = freq; + paramCache["order"] = order; + } - this->channel = config->getChannels()[0]; - this->biquads = std::vector>(); - auto type = config->getString("combo_type"); - if (type == "lr_lowpass") - { - this->linkwitzRiley(freq, order, FilterType::Lowpass); - } - else if (type == "lr_highpass") - { - this->linkwitzRiley(freq, order, FilterType::Highpass); - } - else if (type == "bw_highpass") - { - this->butterworth(freq, order, FilterType::Highpass); - } - else if (type == "bw_lowpass") - { - this->butterworth(freq, order, FilterType::Highpass); - } - else - { - throw std::invalid_argument("Invalid combo filter type"); - } - } - }; -}; \ No newline at end of file + this->channel = config->getChannels()[0]; + this->biquads = std::vector>(); + auto type = config->getString("combo_type"); + if (type == "lr_lowpass") { + this->linkwitzRiley(freq, order, FilterType::Lowpass); + } else if (type == "lr_highpass") { + this->linkwitzRiley(freq, order, FilterType::Highpass); + } else if (type == "bw_highpass") { + this->butterworth(freq, order, FilterType::Highpass); + } else if (type == "bw_lowpass") { + this->butterworth(freq, order, FilterType::Highpass); + } else { + throw std::invalid_argument("Invalid combo filter type"); + } + } +}; +}; // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/CentralAudioBuffer.h b/components/spotify/cspot/bell/main/audio-dsp/include/CentralAudioBuffer.h index c2723da5..d55f3ed7 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/CentralAudioBuffer.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/CentralAudioBuffer.h @@ -2,10 +2,10 @@ #include #include +#include #include #include #include -#include #include "BellUtils.h" #include "CircularBuffer.h" @@ -70,9 +70,9 @@ class CentralAudioBuffer { */ void clearBuffer() { std::scoped_lock lock(this->dataAccessMutex); - //size_t exceptSize = currentSampleRate + (sizeof(AudioChunk) - (currentSampleRate % sizeof(AudioChunk))); - hasChunk = false; + audioBuffer->emptyBuffer(); + hasChunk = false; } void emptyCompletely() { @@ -106,10 +106,10 @@ class CentralAudioBuffer { } } - AudioChunk currentChunk = { }; + AudioChunk currentChunk = {}; bool hasChunk = false; - AudioChunk lastReadChunk = { }; + AudioChunk lastReadChunk = {}; AudioChunk* readChunk() { std::scoped_lock lock(this->dataAccessMutex); diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/Compressor.h b/components/spotify/cspot/bell/main/audio-dsp/include/Compressor.h index 4308160d..9d1995c3 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/Compressor.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/Compressor.h @@ -1,103 +1,102 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include +#include // for expf +#include // for uint32_t +#include // for map +#include // for unique_ptr +#include // for scoped_lock +#include // for string, operator< +#include // for vector -#include "Biquad.h" -#include "AudioTransform.h" +#include "AudioTransform.h" // for AudioTransform +#include "StreamInfo.h" // for StreamInfo +#include "TransformConfig.h" // for TransformConfig -#define pow10f(x) expf(2.302585092994046f*x) +#define pow10f(x) expf(2.302585092994046f * x) // This is a fast approximation to log2() // Y = C[0]*F*F*F + C[1]*F*F + C[2]*F + C[3] + E; -float log2f_approx(float X); +float log2f_approx(float X); -#define log10f_fast(x) (log2f_approx(x)*0.3010299956639812f) +#define log10f_fast(x) (log2f_approx(x) * 0.3010299956639812f) -namespace bell -{ - class Compressor : public bell::AudioTransform - { - private: - std::vector channels; - std::vector tmp; +namespace bell { +class Compressor : public bell::AudioTransform { + private: + std::vector channels; + std::vector tmp; - std::map paramCache; + std::map paramCache; - float attack; - float release; - float threshold; - float factor; - float clipLimit; - float makeupGain; + float attack; + float release; + float threshold; + float factor; + float clipLimit; + float makeupGain; - float lastLoudness = -100.0f; + float lastLoudness = -100.0f; - float sampleRate = 44100; + float sampleRate = 44100; - public: - Compressor(); - ~Compressor(){}; + public: + Compressor(); + ~Compressor(){}; - void configure(std::vector channels, float attack, float release, float threshold, float factor, float makeupGain); + void configure(std::vector channels, float attack, float release, + float threshold, float factor, float makeupGain); - void sumChannels(std::unique_ptr &data); - void calLoudness(); - void calGain(); + void sumChannels(std::unique_ptr& data); + void calLoudness(); + void calGain(); - void applyGain(std::unique_ptr &data); + void applyGain(std::unique_ptr& data); - void reconfigure() override - { - std::scoped_lock lock(this->accessMutex); - auto newChannels = config->getChannels(); - - float newAttack = config->getFloat("attack"); - float newRelease = config->getFloat("release"); - float newThreshold = config->getFloat("threshold"); - float newFactor = config->getFloat("factor"); - float newMakeupGain = config->getFloat("makeup_gain"); + void reconfigure() override { + std::scoped_lock lock(this->accessMutex); + auto newChannels = config->getChannels(); - if (paramCache["attack"] == newAttack && - paramCache["release"] == newRelease && - paramCache["threshold"] == newThreshold && - paramCache["factor"] == newFactor && - paramCache["makeup_gain"] == newMakeupGain) - { - return; - } - else - { + float newAttack = config->getFloat("attack"); + float newRelease = config->getFloat("release"); + float newThreshold = config->getFloat("threshold"); + float newFactor = config->getFloat("factor"); + float newMakeupGain = config->getFloat("makeup_gain"); - paramCache["attack"] = newAttack; - paramCache["release"] = newRelease; - paramCache["threshold"] = newThreshold; - paramCache["factor"] = newFactor; - paramCache["makeup_gain"] = newMakeupGain; - } + if (paramCache["attack"] == newAttack && + paramCache["release"] == newRelease && + paramCache["threshold"] == newThreshold && + paramCache["factor"] == newFactor && + paramCache["makeup_gain"] == newMakeupGain) { + return; + } else { - this->configure(newChannels, newAttack, newRelease, newThreshold, newFactor, newMakeupGain); - } + paramCache["attack"] = newAttack; + paramCache["release"] = newRelease; + paramCache["threshold"] = newThreshold; + paramCache["factor"] = newFactor; + paramCache["makeup_gain"] = newMakeupGain; + } - // void fromJSON(cJSON* json) override { - // // get field channels - // channels = jsonGetChannels(json); - // float attack = jsonGetNumber(json, "attack", false, 0); - // float release = jsonGetNumber(json, "release", false, 0); - // float factor = jsonGetNumber(json, "factor", false, 4); - // float makeupGain = jsonGetNumber(json, "makeup_gain", false, 0); - // float threshold = jsonGetNumber(json, "threshold", false, 0); + this->configure(newChannels, newAttack, newRelease, newThreshold, newFactor, + newMakeupGain); + } - // this->configure(attack, release, clipLimit, threshold, factor, makeupGain); - // } + // void fromJSON(cJSON* json) override { + // // get field channels + // channels = jsonGetChannels(json); + // float attack = jsonGetNumber(json, "attack", false, 0); + // float release = jsonGetNumber(json, "release", false, 0); + // float factor = jsonGetNumber(json, "factor", false, 4); + // float makeupGain = jsonGetNumber(json, "makeup_gain", false, 0); + // float threshold = jsonGetNumber(json, "threshold", false, 0); - std::unique_ptr process(std::unique_ptr data) override; - void sampleRateChanged(uint32_t sampleRate) override { this->sampleRate = sampleRate; }; - }; + // this->configure(attack, release, clipLimit, threshold, factor, makeupGain); + // } + + std::unique_ptr process( + std::unique_ptr data) override; + void sampleRateChanged(uint32_t sampleRate) override { + this->sampleRate = sampleRate; + }; }; +}; // namespace bell diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/Gain.h b/components/spotify/cspot/bell/main/audio-dsp/include/Gain.h index 8948b223..f8151a9e 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/Gain.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/Gain.h @@ -1,40 +1,41 @@ #pragma once -#include -#include -#include +#include // for unique_ptr +#include // for scoped_lock +#include // for vector -#include "AudioTransform.h" +#include "AudioTransform.h" // for AudioTransform +#include "StreamInfo.h" // for StreamInfo +#include "TransformConfig.h" // for TransformConfig -namespace bell -{ - class Gain : public bell::AudioTransform - { - private: - float gainFactor = 1.0f; +namespace bell { +class Gain : public bell::AudioTransform { + private: + float gainFactor = 1.0f; - std::vector channels; + std::vector channels; - public: - Gain(); - ~Gain() {}; - - float gainDb = 0.0; - - void configure(std::vector channels, float gainDB); + public: + Gain(); + ~Gain(){}; - std::unique_ptr process(std::unique_ptr data) override; + float gainDb = 0.0; - void reconfigure() override { - std::scoped_lock lock(this->accessMutex); - float gain = config->getFloat("gain"); - this->channels = config->getChannels(); + void configure(std::vector channels, float gainDB); - if (gainDb == gain) { - return; - } + std::unique_ptr process( + std::unique_ptr data) override; - this->configure(channels, gain); - } - }; -} \ No newline at end of file + void reconfigure() override { + std::scoped_lock lock(this->accessMutex); + float gain = config->getFloat("gain"); + this->channels = config->getChannels(); + + if (gainDb == gain) { + return; + } + + this->configure(channels, gain); + } +}; +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/JSONTransformConfig.h b/components/spotify/cspot/bell/main/audio-dsp/include/JSONTransformConfig.h index 9ee15229..3b63680e 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/JSONTransformConfig.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/JSONTransformConfig.h @@ -3,108 +3,87 @@ #include "TransformConfig.h" #include "cJSON.h" -namespace bell -{ - class JSONTransformConfig : public bell::TransformConfig - { - private: - cJSON *json; +namespace bell { +class JSONTransformConfig : public bell::TransformConfig { + private: + cJSON* json; - public: - JSONTransformConfig(cJSON *body) - { - this->json = body; - }; - ~JSONTransformConfig(){}; + public: + JSONTransformConfig(cJSON* body) { this->json = body; }; + ~JSONTransformConfig(){}; - std::string rawGetString(const std::string &field) override - { - cJSON *value = cJSON_GetObjectItem(json, field.c_str()); + std::string rawGetString(const std::string& field) override { + cJSON* value = cJSON_GetObjectItem(json, field.c_str()); - if (value != NULL && cJSON_IsString(value)) - { - return std::string(value->valuestring); - } + if (value != NULL && cJSON_IsString(value)) { + return std::string(value->valuestring); + } - return "invalid"; + return "invalid"; + } + + std::vector rawGetIntArray(const std::string& field) override { + std::vector result; + + cJSON* value = cJSON_GetObjectItem(json, field.c_str()); + + if (value != NULL && cJSON_IsArray(value)) { + for (int i = 0; i < cJSON_GetArraySize(value); i++) { + cJSON* item = cJSON_GetArrayItem(value, i); + if (item != NULL && cJSON_IsNumber(item)) { + result.push_back(item->valueint); } + } + } - std::vector rawGetIntArray(const std::string &field) override - { - std::vector result; + return result; + } - cJSON *value = cJSON_GetObjectItem(json, field.c_str()); + std::vector rawGetFloatArray(const std::string& field) override { + std::vector result; - if (value != NULL && cJSON_IsArray(value)) - { - for (int i = 0; i < cJSON_GetArraySize(value); i++) - { - cJSON *item = cJSON_GetArrayItem(value, i); - if (item != NULL && cJSON_IsNumber(item)) - { - result.push_back(item->valueint); - } - } - } + cJSON* value = cJSON_GetObjectItem(json, field.c_str()); - return result; + if (value != NULL && cJSON_IsArray(value)) { + for (int i = 0; i < cJSON_GetArraySize(value); i++) { + cJSON* item = cJSON_GetArrayItem(value, i); + if (item != NULL && cJSON_IsNumber(item)) { + result.push_back(item->valuedouble); } + } + } - std::vector rawGetFloatArray(const std::string &field) override - { - std::vector result; + return result; + } - cJSON *value = cJSON_GetObjectItem(json, field.c_str()); + int rawGetInt(const std::string& field) override { + cJSON* value = cJSON_GetObjectItem(json, field.c_str()); - if (value != NULL && cJSON_IsArray(value)) - { - for (int i = 0; i < cJSON_GetArraySize(value); i++) - { - cJSON *item = cJSON_GetArrayItem(value, i); - if (item != NULL && cJSON_IsNumber(item)) - { - result.push_back(item->valuedouble); - } - } - } + if (value != NULL && cJSON_IsNumber(value)) { + return (int)value->valueint; + } - return result; - } + return invalidInt; + } - int rawGetInt(const std::string &field) override - { - cJSON *value = cJSON_GetObjectItem(json, field.c_str()); + bool isArray(const std::string& field) override { + cJSON* value = cJSON_GetObjectItem(json, field.c_str()); - if (value != NULL && cJSON_IsNumber(value)) - { - return (int)value->valueint; - } + if (value != NULL && cJSON_IsArray(value)) { + return true; + } - return invalidInt; - } + return false; + } - bool isArray(const std::string &field) override - { - cJSON *value = cJSON_GetObjectItem(json, field.c_str()); + float rawGetFloat(const std::string& field) override { + cJSON* value = cJSON_GetObjectItem(json, field.c_str()); - if (value != NULL && cJSON_IsArray(value)) - { - return true; - } + if (value != NULL && cJSON_IsNumber(value)) { + return (float)value->valuedouble; + } - return false; - } - - float rawGetFloat(const std::string &field) override - { - cJSON *value = cJSON_GetObjectItem(json, field.c_str()); - - if (value != NULL && cJSON_IsNumber(value)) - { - return (float)value->valuedouble; - } - - return invalidInt; - } - }; -} \ No newline at end of file + return invalidInt; + } +}; +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/StreamInfo.h b/components/spotify/cspot/bell/main/audio-dsp/include/StreamInfo.h index 313a3824..bac4661b 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/StreamInfo.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/StreamInfo.h @@ -1,36 +1,28 @@ #pragma once #include -#include #include +#include -namespace bell -{ - enum class Channels { - LEFT, - RIGHT, - LEFT_RIGHT - }; - - enum class SampleRate : uint32_t - { - SR_44100 = 44100, - SR_48000 = 48000, - }; +namespace bell { +enum class Channels { LEFT, RIGHT, LEFT_RIGHT }; - enum class BitWidth : uint32_t - { - BW_16 = 16, - BW_24 = 24, - BW_32 = 32, - }; +enum class SampleRate : uint32_t { + SR_44100 = 44100, + SR_48000 = 48000, +}; - typedef struct - { - float** data; - BitWidth bitwidth; - int numChannels; - SampleRate sampleRate; - size_t numSamples; - } StreamInfo; -}; \ No newline at end of file +enum class BitWidth : uint32_t { + BW_16 = 16, + BW_24 = 24, + BW_32 = 32, +}; + +typedef struct { + float** data; + BitWidth bitwidth; + int numChannels; + SampleRate sampleRate; + size_t numSamples; +} StreamInfo; +}; // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-dsp/include/TransformConfig.h b/components/spotify/cspot/bell/main/audio-dsp/include/TransformConfig.h index c0809fd3..942db428 100644 --- a/components/spotify/cspot/bell/main/audio-dsp/include/TransformConfig.h +++ b/components/spotify/cspot/bell/main/audio-dsp/include/TransformConfig.h @@ -1,134 +1,112 @@ #pragma once -#include -#include -#include -#include #include #include +#include +#include +#include +#include -namespace bell -{ - class TransformConfig - { - protected: - int invalidInt = -0x7C; - std::string invalidString = "_invalid"; +namespace bell { +class TransformConfig { + protected: + int invalidInt = -0x7C; + std::string invalidString = "_invalid"; - public: - TransformConfig() = default; - virtual ~TransformConfig() = default; + public: + TransformConfig() = default; + virtual ~TransformConfig() = default; - int currentVolume = 60; + int currentVolume = 60; - virtual std::string rawGetString(const std::string &field) = 0; + virtual std::string rawGetString(const std::string& field) = 0; - virtual int rawGetInt(const std::string &field) = 0; - virtual bool isArray(const std::string &field) = 0; + virtual int rawGetInt(const std::string& field) = 0; + virtual bool isArray(const std::string& field) = 0; - virtual float rawGetFloat(const std::string &field) = 0; - virtual std::vector rawGetFloatArray(const std::string &field) = 0; - virtual std::vector rawGetIntArray(const std::string &field) = 0; + virtual float rawGetFloat(const std::string& field) = 0; + virtual std::vector rawGetFloatArray(const std::string& field) = 0; + virtual std::vector rawGetIntArray(const std::string& field) = 0; - typedef std::variant Value; - std::map> rawValues; + typedef std::variant Value; + std::map> rawValues; - Value getRawValue(const std::string &field) - { - int index = this->currentVolume * (rawValues[field].size()) / 100; - if (index >= rawValues[field].size()) - index = rawValues[field].size() - 1; - return rawValues[field][index]; + Value getRawValue(const std::string& field) { + int index = this->currentVolume * (rawValues[field].size()) / 100; + if (index >= rawValues[field].size()) + index = rawValues[field].size() - 1; + return rawValues[field][index]; + } + + std::string getString(const std::string& field, bool isRequired = false, + std::string defaultValue = "") { + if (rawValues.count(field) == 0) { + rawValues[field] = std::vector({Value(rawGetString(field))}); + } + auto val = std::get(getRawValue(field)); + if (val == invalidString) { + if (isRequired) + throw std::invalid_argument("Field " + field + " is required"); + else + return defaultValue; + } else + return val; + } + + int getInt(const std::string& field, bool isRequired = false, + int defaultValue = 0) { + if (rawValues.count(field) == 0) { + if (isArray(field)) { + rawValues[field] = std::vector(); + for (auto f : rawGetIntArray(field)) { + rawValues[field].push_back(f); } + } else { + rawValues[field] = std::vector({Value(rawGetInt(field))}); + } + } - std::string getString(const std::string &field, bool isRequired = false, std::string defaultValue = "") - { - if (rawValues.count(field) == 0) - { - rawValues[field] = std::vector({Value(rawGetString(field))}); - } - auto val = std::get(getRawValue(field)); - if (val == invalidString) - { - if (isRequired) - throw std::invalid_argument("Field " + field + " is required"); - else - return defaultValue; - } - else - return val; + auto val = std::get(getRawValue(field)); + if (val == invalidInt) { + if (isRequired) + throw std::invalid_argument("Field " + field + " is required"); + else + return defaultValue; + } else + return val; + } + + float getFloat(const std::string& field, bool isRequired = false, + float defaultValue = 0) { + if (rawValues.count(field) == 0) { + if (isArray(field)) { + + rawValues[field] = std::vector(); + for (auto f : rawGetFloatArray(field)) { + rawValues[field].push_back(f); } + } else { + rawValues[field] = std::vector({Value(rawGetFloat(field))}); + } + } + auto val = std::get(getRawValue(field)); + if (val == invalidInt) { + if (isRequired) + throw std::invalid_argument("Field " + field + " is required"); + else + return defaultValue; + } else + return val; + } - int getInt(const std::string &field, bool isRequired = false, int defaultValue = 0) - { - if (rawValues.count(field) == 0) - { - if (isArray(field)) - { - rawValues[field] = std::vector(); - for (auto f : rawGetIntArray(field)) - { - rawValues[field].push_back(f); - } - } - else - { - rawValues[field] = std::vector({Value(rawGetInt(field))}); - } - } + std::vector getChannels() { + auto channel = getInt("channel", false, invalidInt); - auto val = std::get(getRawValue(field)); - if (val == invalidInt) - { - if (isRequired) - throw std::invalid_argument("Field " + field + " is required"); - else - return defaultValue; - } - else - return val; - } + if (channel != invalidInt) { + return std::vector({channel}); + } - float getFloat(const std::string &field, bool isRequired = false, float defaultValue = 0) - { - if (rawValues.count(field) == 0) - { - if (isArray(field)) - { - - rawValues[field] = std::vector(); - for (auto f : rawGetFloatArray(field)) - { - rawValues[field].push_back(f); - } - } - else - { - rawValues[field] = std::vector({ Value(rawGetFloat(field)) }); - } - } - auto val = std::get(getRawValue(field)); - if (val == invalidInt) - { - if (isRequired) - throw std::invalid_argument("Field " + field + " is required"); - else - return defaultValue; - } - else - return val; - } - - std::vector getChannels() - { - auto channel = getInt("channel", false, invalidInt); - - if (channel != invalidInt) - { - return std::vector({channel}); - } - - return rawGetIntArray("channels"); - } - }; -} \ No newline at end of file + return rawGetIntArray("channels"); + } +}; +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/AC101AudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/AC101AudioSink.cpp index 5e83f10d..e07f65a2 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/AC101AudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/AC101AudioSink.cpp @@ -2,45 +2,42 @@ #include "driver/i2s.h" -AC101AudioSink::AC101AudioSink() -{ - // Disable software volume control, all handled by ::volumeChanged - softwareVolumeControl = false; +AC101AudioSink::AC101AudioSink() { + // Disable software volume control, all handled by ::volumeChanged + softwareVolumeControl = false; - i2s_config_t i2s_config = { + i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX - .sample_rate = 44100, - .bits_per_sample = (i2s_bits_per_sample_t)16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S, - .intr_alloc_flags = 0, //Default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 512, - .use_apll = true, - .tx_desc_auto_clear = true //Auto clear tx descriptor on underflow - }; + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX + .sample_rate = 44100, + .bits_per_sample = (i2s_bits_per_sample_t)16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S, + .intr_alloc_flags = 0, //Default interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 512, + .use_apll = true, + .tx_desc_auto_clear = true //Auto clear tx descriptor on underflow + }; - i2s_pin_config_t pin_config = { - .bck_io_num = 27, - .ws_io_num = 26, - .data_out_num = 25, - .data_in_num = -1 //Not used - }; + i2s_pin_config_t pin_config = { + .bck_io_num = 27, + .ws_io_num = 26, + .data_out_num = 25, + .data_in_num = -1 //Not used + }; - dac = &dac_a1s; + dac = &dac_a1s; - dac->init(0, 0, &i2s_config); - dac->speaker(false); - dac->power(ADAC_ON); + dac->init(0, 0, &i2s_config); + dac->speaker(false); + dac->power(ADAC_ON); - startI2sFeed(); + startI2sFeed(); } -AC101AudioSink::~AC101AudioSink() -{ -} +AC101AudioSink::~AC101AudioSink() {} void AC101AudioSink::volumeChanged(uint16_t volume) { - dac->volume(volume, volume); + dac->volume(volume, volume); } diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/BufferedAudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/BufferedAudioSink.cpp index 4d849fc3..e32a9c7a 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/BufferedAudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/BufferedAudioSink.cpp @@ -1,47 +1,45 @@ #include "BufferedAudioSink.h" #include "driver/i2s.h" -#include "freertos/task.h" #include "freertos/ringbuf.h" +#include "freertos/task.h" RingbufHandle_t dataBuffer; -static void i2sFeed(void *pvParameters) -{ - while (true) - { - size_t itemSize; - char *item = (char *)xRingbufferReceiveUpTo(dataBuffer, &itemSize, portMAX_DELAY, 512); - if (item != NULL) - { - size_t written = 0; - while (written < itemSize) - { - i2s_write((i2s_port_t)0, item, itemSize, &written, portMAX_DELAY); - } - vRingbufferReturnItem(dataBuffer, (void *)item); - } +static void i2sFeed(void* pvParameters) { + while (true) { + size_t itemSize; + char* item = (char*)xRingbufferReceiveUpTo(dataBuffer, &itemSize, + portMAX_DELAY, 512); + if (item != NULL) { + size_t written = 0; + while (written < itemSize) { + i2s_write((i2s_port_t)0, item, itemSize, &written, portMAX_DELAY); + } + vRingbufferReturnItem(dataBuffer, (void*)item); } + } } -void BufferedAudioSink::startI2sFeed(size_t buf_size) -{ - dataBuffer = xRingbufferCreate(buf_size, RINGBUF_TYPE_BYTEBUF); - xTaskCreatePinnedToCore(&i2sFeed, "i2sFeed", 4096, NULL, 10, NULL, tskNO_AFFINITY); +void BufferedAudioSink::startI2sFeed(size_t buf_size) { + dataBuffer = xRingbufferCreate(buf_size, RINGBUF_TYPE_BYTEBUF); + xTaskCreatePinnedToCore(&i2sFeed, "i2sFeed", 4096, NULL, 10, NULL, + tskNO_AFFINITY); } -void BufferedAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes) -{ - feedPCMFramesInternal(buffer, bytes); +void BufferedAudioSink::feedPCMFrames(const uint8_t* buffer, size_t bytes) { + feedPCMFramesInternal(buffer, bytes); } -void BufferedAudioSink::feedPCMFramesInternal(const void *pvItem, size_t xItemSize) -{ - xRingbufferSend(dataBuffer, pvItem, xItemSize, portMAX_DELAY); +void BufferedAudioSink::feedPCMFramesInternal(const void* pvItem, + size_t xItemSize) { + xRingbufferSend(dataBuffer, pvItem, xItemSize, portMAX_DELAY); } -bool BufferedAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) { - // TODO override this for sinks with custom mclk - i2s_set_clk((i2s_port_t)0, sampleRate, (i2s_bits_per_sample_t)bitDepth, (i2s_channel_t)channelCount); - return true; +bool BufferedAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, + uint8_t bitDepth) { + // TODO override this for sinks with custom mclk + i2s_set_clk((i2s_port_t)0, sampleRate, (i2s_bits_per_sample_t)bitDepth, + (i2s_channel_t)channelCount); + return true; } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/ES8311AudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/ES8311AudioSink.cpp index 62041593..aa9ff9fd 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/ES8311AudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/ES8311AudioSink.cpp @@ -1,106 +1,101 @@ #include "ES8311AudioSink.h" extern "C" { - #include "es8311.h" +#include "es8311.h" } -ES8311AudioSink::ES8311AudioSink() -{ - this->softwareVolumeControl = false; - esp_err_t ret_val = ESP_OK; - Es8311Config cfg = { - .esMode = ES_MODE_SLAVE, - .i2c_port_num = I2C_NUM_0, - .i2c_cfg = { - .mode = I2C_MODE_MASTER, - .sda_io_num = 1, - .scl_io_num = 2, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - }, - .dacOutput = (DacOutput) (DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2), - .adcInput = ADC_INPUT_LINPUT1_RINPUT1, - }; - cfg.i2c_cfg.master.clk_speed = 100000; - Es8311Init(&cfg); - Es8311SetBitsPerSample(ES_MODULE_DAC, BIT_LENGTH_16BITS); - Es8311ConfigFmt(ES_MODULE_DAC, ES_I2S_NORMAL); - Es8311SetVoiceVolume(60); - Es8311Start(ES_MODULE_DAC); - ES8311WriteReg(ES8311_CLK_MANAGER_REG01, 0xbf); - ES8311WriteReg(ES8311_CLK_MANAGER_REG02, 0x18); +ES8311AudioSink::ES8311AudioSink() { + this->softwareVolumeControl = false; + esp_err_t ret_val = ESP_OK; + Es8311Config cfg = { + .esMode = ES_MODE_SLAVE, + .i2c_port_num = I2C_NUM_0, + .i2c_cfg = + { + .mode = I2C_MODE_MASTER, + .sda_io_num = 1, + .scl_io_num = 2, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + }, + .dacOutput = (DacOutput)(DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | + DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2), + .adcInput = ADC_INPUT_LINPUT1_RINPUT1, + }; + cfg.i2c_cfg.master.clk_speed = 100000; + Es8311Init(&cfg); + Es8311SetBitsPerSample(ES_MODULE_DAC, BIT_LENGTH_16BITS); + Es8311ConfigFmt(ES_MODULE_DAC, ES_I2S_NORMAL); + Es8311SetVoiceVolume(60); + Es8311Start(ES_MODULE_DAC); + ES8311WriteReg(ES8311_CLK_MANAGER_REG01, 0xbf); + ES8311WriteReg(ES8311_CLK_MANAGER_REG02, 0x18); - // .codec_mode = AUDIO_HAL_CODEC_MODE_DECODE, - // .i2s_iface = { - // .mode = AUDIO_HAL_MODE_SLAVE, - // .fmt = AUDIO_HAL_I2S_NORMAL, - // .samples = AUDIO_HAL_44K_SAMPLES, - // .bits = AUDIO_HAL_BIT_LENGTH_16BITS, - // }, - // }; + // .codec_mode = AUDIO_HAL_CODEC_MODE_DECODE, + // .i2s_iface = { + // .mode = AUDIO_HAL_MODE_SLAVE, + // .fmt = AUDIO_HAL_I2S_NORMAL, + // .samples = AUDIO_HAL_44K_SAMPLES, + // .bits = AUDIO_HAL_BIT_LENGTH_16BITS, + // }, + // }; - // ret_val |= es8311_codec_init(&cfg); - // ret_val |= es8311_set_bits_per_sample(cfg.i2s_iface.bits); - // ret_val |= es8311_config_fmt((es_i2s_fmt_t) cfg.i2s_iface.fmt); - // ret_val |= es8311_codec_set_voice_volume(60); - // ret_val |= es8311_codec_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START); - // ret_val |= es8311_codec_set_clk(); + // ret_val |= es8311_codec_init(&cfg); + // ret_val |= es8311_set_bits_per_sample(cfg.i2s_iface.bits); + // ret_val |= es8311_config_fmt((es_i2s_fmt_t) cfg.i2s_iface.fmt); + // ret_val |= es8311_codec_set_voice_volume(60); + // ret_val |= es8311_codec_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START); + // ret_val |= es8311_codec_set_clk(); - i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX - .sample_rate = 44100, - .bits_per_sample = (i2s_bits_per_sample_t)16, - .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 2-channels - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S, - .intr_alloc_flags = 0, // Default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 512, - .use_apll = false, - .tx_desc_auto_clear = true, // Auto clear tx descriptor on underflow - }; + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX + .sample_rate = 44100, + .bits_per_sample = (i2s_bits_per_sample_t)16, + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // 2-channels + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S, + .intr_alloc_flags = 0, // Default interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 512, + .use_apll = false, + .tx_desc_auto_clear = true, // Auto clear tx descriptor on underflow + }; - i2s_pin_config_t pin_config = { - .mck_io_num = 42, - .bck_io_num = 40, - .ws_io_num = 41, - .data_out_num = 39, - .data_in_num = -1, - }; + i2s_pin_config_t pin_config = { + .mck_io_num = 42, + .bck_io_num = 40, + .ws_io_num = 41, + .data_out_num = 39, + .data_in_num = -1, + }; - int err; + int err; - err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); - if (err != ESP_OK) - { - ESP_LOGE("OI", "i2s driver installation error: %d", err); - } + err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); + if (err != ESP_OK) { + ESP_LOGE("OI", "i2s driver installation error: %d", err); + } - err = i2s_set_pin((i2s_port_t)0, &pin_config); - if (err != ESP_OK) - { - ESP_LOGE("OI", "i2s set pin error: %d", err); - } + err = i2s_set_pin((i2s_port_t)0, &pin_config); + if (err != ESP_OK) { + ESP_LOGE("OI", "i2s set pin error: %d", err); + } - // PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); - // REG_SET_FIELD(PIN_CTRL, CLK_OUT1, 0); - // ESP_LOGI("OI", "MCLK output on CLK_OUT1"); + // PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + // REG_SET_FIELD(PIN_CTRL, CLK_OUT1, 0); + // ESP_LOGI("OI", "MCLK output on CLK_OUT1"); - startI2sFeed(); + startI2sFeed(); } -void ES8311AudioSink::volumeChanged(uint16_t volume) -{ - Es8311SetVoiceVolume(volume); +void ES8311AudioSink::volumeChanged(uint16_t volume) { + Es8311SetVoiceVolume(volume); } -void ES8311AudioSink::writeReg(uint8_t reg_add, uint8_t data) -{ -} +void ES8311AudioSink::writeReg(uint8_t reg_add, uint8_t data) {} void ES8311AudioSink::setSampleRate(uint32_t sampleRate) { - std::cout << "ES8311AudioSink::setSampleRate(" << sampleRate << ")" << std::endl; - // i2s set sample rate - es8311_Codec_Startup(0, sampleRate); + std::cout << "ES8311AudioSink::setSampleRate(" << sampleRate << ")" + << std::endl; + // i2s set sample rate + es8311_Codec_Startup(0, sampleRate); } -ES8311AudioSink::~ES8311AudioSink() -{ -} +ES8311AudioSink::~ES8311AudioSink() {} diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/ES8388AudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/ES8388AudioSink.cpp index b5b5f312..bd450e26 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/ES8388AudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/ES8388AudioSink.cpp @@ -1,150 +1,145 @@ #include "ES8388AudioSink.h" struct es8388_cmd_s { - uint8_t reg; - uint8_t value; + uint8_t reg; + uint8_t value; }; -ES8388AudioSink::ES8388AudioSink() -{ - // configure i2c - i2c_config = { - .mode = I2C_MODE_MASTER, - .sda_io_num = 33, - .scl_io_num = 32, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - }; +ES8388AudioSink::ES8388AudioSink() { + // configure i2c + i2c_config = { + .mode = I2C_MODE_MASTER, + .sda_io_num = 33, + .scl_io_num = 32, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + }; - i2c_config.master.clk_speed = 100000; + i2c_config.master.clk_speed = 100000; - i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX - .sample_rate = 44100, - .bits_per_sample = (i2s_bits_per_sample_t)16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, - .intr_alloc_flags = 0, //Default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 512, - .use_apll = true, - .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow - .fixed_mclk = 256 * 44100 - }; + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX + .sample_rate = 44100, + .bits_per_sample = (i2s_bits_per_sample_t)16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, + .intr_alloc_flags = 0, //Default interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 512, + .use_apll = true, + .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow + .fixed_mclk = 256 * 44100}; - i2s_pin_config_t pin_config = { - .bck_io_num = 27, - .ws_io_num = 25, - .data_out_num = 26, - .data_in_num = -1 //Not used - }; + i2s_pin_config_t pin_config = { + .bck_io_num = 27, + .ws_io_num = 25, + .data_out_num = 26, + .data_in_num = -1 //Not used + }; - int err; + int err; - err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); - if (err != ESP_OK) { - ESP_LOGE("OI", "i2s driver installation error: %d", err); - } + err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); + if (err != ESP_OK) { + ESP_LOGE("OI", "i2s driver installation error: %d", err); + } - err = i2s_set_pin((i2s_port_t)0, &pin_config); - if (err != ESP_OK) { - ESP_LOGE("OI", "i2s set pin error: %d", err); - } + err = i2s_set_pin((i2s_port_t)0, &pin_config); + if (err != ESP_OK) { + ESP_LOGE("OI", "i2s set pin error: %d", err); + } - err = i2c_param_config(0, &i2c_config); - if (err != ESP_OK) { - ESP_LOGE("OI", "i2c param config error: %d", err); - } - - err = i2c_driver_install(0, I2C_MODE_MASTER, 0, 0, 0); - if (err != ESP_OK) { - ESP_LOGE("OI", "i2c driver installation error: %d", err); - } + err = i2c_param_config(0, &i2c_config); + if (err != ESP_OK) { + ESP_LOGE("OI", "i2c param config error: %d", err); + } - i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); + err = i2c_driver_install(0, I2C_MODE_MASTER, 0, 0, 0); + if (err != ESP_OK) { + ESP_LOGE("OI", "i2c driver installation error: %d", err); + } - err = i2c_master_start(i2c_cmd); - if (err != ESP_OK) { - ESP_LOGE("OI", "i2c master start error: %d", err); - } + i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); - /* mute DAC during setup, power up all systems, slave mode */ - writeReg(ES8388_DACCONTROL3, 0x04); - writeReg(ES8388_CONTROL2, 0x50); - writeReg(ES8388_CHIPPOWER, 0x00); - writeReg(ES8388_MASTERMODE, 0x00); + err = i2c_master_start(i2c_cmd); + if (err != ESP_OK) { + ESP_LOGE("OI", "i2c master start error: %d", err); + } - /* power up DAC and enable LOUT1+2 / ROUT1+2, ADC sample rate = DAC sample rate */ - writeReg(ES8388_DACPOWER, 0x3e); - writeReg(ES8388_CONTROL1, 0x12); + /* mute DAC during setup, power up all systems, slave mode */ + writeReg(ES8388_DACCONTROL3, 0x04); + writeReg(ES8388_CONTROL2, 0x50); + writeReg(ES8388_CHIPPOWER, 0x00); + writeReg(ES8388_MASTERMODE, 0x00); - /* DAC I2S setup: 16 bit word length, I2S format; MCLK / Fs = 256*/ - writeReg(ES8388_DACCONTROL1, 0x18); - writeReg(ES8388_DACCONTROL2, 0x02); + /* power up DAC and enable LOUT1+2 / ROUT1+2, ADC sample rate = DAC sample rate */ + writeReg(ES8388_DACPOWER, 0x3e); + writeReg(ES8388_CONTROL1, 0x12); - /* DAC to output route mixer configuration: ADC MIX TO OUTPUT */ - writeReg(ES8388_DACCONTROL16, 0x1B); - writeReg(ES8388_DACCONTROL17, 0x90); - writeReg(ES8388_DACCONTROL20, 0x90); + /* DAC I2S setup: 16 bit word length, I2S format; MCLK / Fs = 256*/ + writeReg(ES8388_DACCONTROL1, 0x18); + writeReg(ES8388_DACCONTROL2, 0x02); - /* DAC and ADC use same LRCK, enable MCLK input; output resistance setup */ - writeReg(ES8388_DACCONTROL21, 0x80); - writeReg(ES8388_DACCONTROL23, 0x00); + /* DAC to output route mixer configuration: ADC MIX TO OUTPUT */ + writeReg(ES8388_DACCONTROL16, 0x1B); + writeReg(ES8388_DACCONTROL17, 0x90); + writeReg(ES8388_DACCONTROL20, 0x90); - /* DAC volume control: 0dB (maximum, unattented) */ - writeReg(ES8388_DACCONTROL5, 0x00); - writeReg(ES8388_DACCONTROL4, 0x00); + /* DAC and ADC use same LRCK, enable MCLK input; output resistance setup */ + writeReg(ES8388_DACCONTROL21, 0x80); + writeReg(ES8388_DACCONTROL23, 0x00); - /* power down ADC while configuring; volume: +9dB for both channels */ - writeReg(ES8388_ADCPOWER, 0xff); - writeReg(ES8388_ADCCONTROL1, 0x88); // +24db + /* DAC volume control: 0dB (maximum, unattented) */ + writeReg(ES8388_DACCONTROL5, 0x00); + writeReg(ES8388_DACCONTROL4, 0x00); - /* select LINPUT2 / RINPUT2 as ADC input; stereo; 16 bit word length, format right-justified, MCLK / Fs = 256 */ - writeReg(ES8388_ADCCONTROL2, 0xf0); // 50 - writeReg(ES8388_ADCCONTROL3, 0x80); // 00 - writeReg(ES8388_ADCCONTROL4, 0x0e); - writeReg(ES8388_ADCCONTROL5, 0x02); + /* power down ADC while configuring; volume: +9dB for both channels */ + writeReg(ES8388_ADCPOWER, 0xff); + writeReg(ES8388_ADCCONTROL1, 0x88); // +24db - /* set ADC volume */ - writeReg(ES8388_ADCCONTROL8, 0x20); - writeReg(ES8388_ADCCONTROL9, 0x20); + /* select LINPUT2 / RINPUT2 as ADC input; stereo; 16 bit word length, format right-justified, MCLK / Fs = 256 */ + writeReg(ES8388_ADCCONTROL2, 0xf0); // 50 + writeReg(ES8388_ADCCONTROL3, 0x80); // 00 + writeReg(ES8388_ADCCONTROL4, 0x0e); + writeReg(ES8388_ADCCONTROL5, 0x02); - /* set LOUT1 / ROUT1 volume: 0dB (unattenuated) */ - writeReg(ES8388_DACCONTROL24, 0x1e); - writeReg(ES8388_DACCONTROL25, 0x1e); + /* set ADC volume */ + writeReg(ES8388_ADCCONTROL8, 0x20); + writeReg(ES8388_ADCCONTROL9, 0x20); - /* set LOUT2 / ROUT2 volume: 0dB (unattenuated) */ - writeReg(ES8388_DACCONTROL26, 0x1e); - writeReg(ES8388_DACCONTROL27, 0x1e); + /* set LOUT1 / ROUT1 volume: 0dB (unattenuated) */ + writeReg(ES8388_DACCONTROL24, 0x1e); + writeReg(ES8388_DACCONTROL25, 0x1e); - /* power up and enable DAC; power up ADC (no MIC bias) */ - writeReg(ES8388_DACPOWER, 0x3c); - writeReg(ES8388_DACCONTROL3, 0x00); - writeReg(ES8388_ADCPOWER, 0x00); + /* set LOUT2 / ROUT2 volume: 0dB (unattenuated) */ + writeReg(ES8388_DACCONTROL26, 0x1e); + writeReg(ES8388_DACCONTROL27, 0x1e); - startI2sFeed(); + /* power up and enable DAC; power up ADC (no MIC bias) */ + writeReg(ES8388_DACPOWER, 0x3c); + writeReg(ES8388_DACCONTROL3, 0x00); + writeReg(ES8388_ADCPOWER, 0x00); + + startI2sFeed(); } -void ES8388AudioSink::writeReg(uint8_t reg_add, uint8_t data) -{ +void ES8388AudioSink::writeReg(uint8_t reg_add, uint8_t data) { - int res = 0; - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - res |= i2c_master_start(cmd); - res |= i2c_master_write_byte(cmd, ES8388_ADDR, ACK_CHECK_EN); - res |= i2c_master_write_byte(cmd, reg_add, ACK_CHECK_EN); - res |= i2c_master_write_byte(cmd, data, ACK_CHECK_EN); - res |= i2c_master_stop(cmd); - res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); + int res = 0; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + res |= i2c_master_start(cmd); + res |= i2c_master_write_byte(cmd, ES8388_ADDR, ACK_CHECK_EN); + res |= i2c_master_write_byte(cmd, reg_add, ACK_CHECK_EN); + res |= i2c_master_write_byte(cmd, data, ACK_CHECK_EN); + res |= i2c_master_stop(cmd); + res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); - if (res != ESP_OK) { - ESP_LOGE("RR", "Unable to write to ES8388: %d", res); - }else{ - ESP_LOGE("RR", "register successfull written."); - } + if (res != ESP_OK) { + ESP_LOGE("RR", "Unable to write to ES8388: %d", res); + } else { + ESP_LOGE("RR", "register successfull written."); + } } -ES8388AudioSink::~ES8388AudioSink() -{ -} +ES8388AudioSink::~ES8388AudioSink() {} diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/ES9018AudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/ES9018AudioSink.cpp index 94dc5817..24143fbc 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/ES9018AudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/ES9018AudioSink.cpp @@ -2,35 +2,31 @@ #include "driver/i2s.h" -ES9018AudioSink::ES9018AudioSink() -{ - i2s_config_t i2s_config = { +ES9018AudioSink::ES9018AudioSink() { + i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX - .sample_rate = 44100, - .bits_per_sample = (i2s_bits_per_sample_t)16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, - .intr_alloc_flags = 0, //Default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 512, - .use_apll = true, - .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow - .fixed_mclk = 384 * 44100 - }; + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX + .sample_rate = 44100, + .bits_per_sample = (i2s_bits_per_sample_t)16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, + .intr_alloc_flags = 0, //Default interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 512, + .use_apll = true, + .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow + .fixed_mclk = 384 * 44100}; - i2s_pin_config_t pin_config = { - .bck_io_num = 27, - .ws_io_num = 32, - .data_out_num = 25, - .data_in_num = -1 //Not used - }; - i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); - i2s_set_pin((i2s_port_t)0, &pin_config); - - startI2sFeed(); + i2s_pin_config_t pin_config = { + .bck_io_num = 27, + .ws_io_num = 32, + .data_out_num = 25, + .data_in_num = -1 //Not used + }; + i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); + i2s_set_pin((i2s_port_t)0, &pin_config); + + startI2sFeed(); } -ES9018AudioSink::~ES9018AudioSink() -{ -} +ES9018AudioSink::~ES9018AudioSink() {} diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/InternalAudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/InternalAudioSink.cpp index 26872a2e..a918f037 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/InternalAudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/InternalAudioSink.cpp @@ -1,35 +1,32 @@ #include "InternalAudioSink.h" #include "driver/i2s.h" -InternalAudioSink::InternalAudioSink() -{ - softwareVolumeControl = true; - usign = true; - #ifdef I2S_MODE_DAC_BUILT_IN +InternalAudioSink::InternalAudioSink() { + softwareVolumeControl = true; + usign = true; +#ifdef I2S_MODE_DAC_BUILT_IN - i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), // Only TX - .sample_rate = (i2s_bits_per_sample_t)44100, - .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S, - .intr_alloc_flags = 0,//ESP_INTR_FLAG_LEVEL1 - .dma_buf_count = 6, - .dma_buf_len = 512, - .use_apll = true, - .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow - .fixed_mclk=-1 - }; + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | + I2S_MODE_DAC_BUILT_IN), // Only TX + .sample_rate = (i2s_bits_per_sample_t)44100, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S, + .intr_alloc_flags = 0, //ESP_INTR_FLAG_LEVEL1 + .dma_buf_count = 6, + .dma_buf_len = 512, + .use_apll = true, + .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow + .fixed_mclk = -1}; - //install and start i2s driver - i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); - //init DAC - i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); - #endif + //install and start i2s driver + i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); + //init DAC + i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); +#endif - startI2sFeed(); + startI2sFeed(); } -InternalAudioSink::~InternalAudioSink() -{ -} +InternalAudioSink::~InternalAudioSink() {} diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/PCM5102AudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/PCM5102AudioSink.cpp index 5cd6ecb6..81f0867a 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/PCM5102AudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/PCM5102AudioSink.cpp @@ -2,35 +2,31 @@ #include "driver/i2s.h" -PCM5102AudioSink::PCM5102AudioSink() -{ - i2s_config_t i2s_config = { +PCM5102AudioSink::PCM5102AudioSink() { + i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX - .sample_rate = 44100, - .bits_per_sample = (i2s_bits_per_sample_t)16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S, - .intr_alloc_flags = 0, //Default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 512, - .use_apll = true, - .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow - .fixed_mclk = 384 * 44100 - }; + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX + .sample_rate = 44100, + .bits_per_sample = (i2s_bits_per_sample_t)16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S, + .intr_alloc_flags = 0, //Default interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 512, + .use_apll = true, + .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow + .fixed_mclk = 384 * 44100}; - i2s_pin_config_t pin_config = { - .bck_io_num = 27, - .ws_io_num = 32, - .data_out_num = 25, - .data_in_num = -1 //Not used - }; - i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); - i2s_set_pin((i2s_port_t)0, &pin_config); + i2s_pin_config_t pin_config = { + .bck_io_num = 27, + .ws_io_num = 32, + .data_out_num = 25, + .data_in_num = -1 //Not used + }; + i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); + i2s_set_pin((i2s_port_t)0, &pin_config); - startI2sFeed(); + startI2sFeed(); } -PCM5102AudioSink::~PCM5102AudioSink() -{ -} +PCM5102AudioSink::~PCM5102AudioSink() {} diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/SPDIFAudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/SPDIFAudioSink.cpp index d6ce712b..1b4644f0 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/SPDIFAudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/SPDIFAudioSink.cpp @@ -5,124 +5,118 @@ // See http://www.hardwarebook.info/S/PDIF for more info on this protocol // Conversion table to biphase code mark (LSB first, ending in 1) static const uint16_t bmc_convert[256] = { - 0x3333, 0xb333, 0xd333, 0x5333, 0xcb33, 0x4b33, 0x2b33, 0xab33, - 0xcd33, 0x4d33, 0x2d33, 0xad33, 0x3533, 0xb533, 0xd533, 0x5533, - 0xccb3, 0x4cb3, 0x2cb3, 0xacb3, 0x34b3, 0xb4b3, 0xd4b3, 0x54b3, - 0x32b3, 0xb2b3, 0xd2b3, 0x52b3, 0xcab3, 0x4ab3, 0x2ab3, 0xaab3, - 0xccd3, 0x4cd3, 0x2cd3, 0xacd3, 0x34d3, 0xb4d3, 0xd4d3, 0x54d3, - 0x32d3, 0xb2d3, 0xd2d3, 0x52d3, 0xcad3, 0x4ad3, 0x2ad3, 0xaad3, - 0x3353, 0xb353, 0xd353, 0x5353, 0xcb53, 0x4b53, 0x2b53, 0xab53, - 0xcd53, 0x4d53, 0x2d53, 0xad53, 0x3553, 0xb553, 0xd553, 0x5553, - 0xcccb, 0x4ccb, 0x2ccb, 0xaccb, 0x34cb, 0xb4cb, 0xd4cb, 0x54cb, - 0x32cb, 0xb2cb, 0xd2cb, 0x52cb, 0xcacb, 0x4acb, 0x2acb, 0xaacb, - 0x334b, 0xb34b, 0xd34b, 0x534b, 0xcb4b, 0x4b4b, 0x2b4b, 0xab4b, - 0xcd4b, 0x4d4b, 0x2d4b, 0xad4b, 0x354b, 0xb54b, 0xd54b, 0x554b, - 0x332b, 0xb32b, 0xd32b, 0x532b, 0xcb2b, 0x4b2b, 0x2b2b, 0xab2b, - 0xcd2b, 0x4d2b, 0x2d2b, 0xad2b, 0x352b, 0xb52b, 0xd52b, 0x552b, - 0xccab, 0x4cab, 0x2cab, 0xacab, 0x34ab, 0xb4ab, 0xd4ab, 0x54ab, - 0x32ab, 0xb2ab, 0xd2ab, 0x52ab, 0xcaab, 0x4aab, 0x2aab, 0xaaab, - 0xcccd, 0x4ccd, 0x2ccd, 0xaccd, 0x34cd, 0xb4cd, 0xd4cd, 0x54cd, - 0x32cd, 0xb2cd, 0xd2cd, 0x52cd, 0xcacd, 0x4acd, 0x2acd, 0xaacd, - 0x334d, 0xb34d, 0xd34d, 0x534d, 0xcb4d, 0x4b4d, 0x2b4d, 0xab4d, - 0xcd4d, 0x4d4d, 0x2d4d, 0xad4d, 0x354d, 0xb54d, 0xd54d, 0x554d, - 0x332d, 0xb32d, 0xd32d, 0x532d, 0xcb2d, 0x4b2d, 0x2b2d, 0xab2d, - 0xcd2d, 0x4d2d, 0x2d2d, 0xad2d, 0x352d, 0xb52d, 0xd52d, 0x552d, - 0xccad, 0x4cad, 0x2cad, 0xacad, 0x34ad, 0xb4ad, 0xd4ad, 0x54ad, - 0x32ad, 0xb2ad, 0xd2ad, 0x52ad, 0xcaad, 0x4aad, 0x2aad, 0xaaad, - 0x3335, 0xb335, 0xd335, 0x5335, 0xcb35, 0x4b35, 0x2b35, 0xab35, - 0xcd35, 0x4d35, 0x2d35, 0xad35, 0x3535, 0xb535, 0xd535, 0x5535, - 0xccb5, 0x4cb5, 0x2cb5, 0xacb5, 0x34b5, 0xb4b5, 0xd4b5, 0x54b5, - 0x32b5, 0xb2b5, 0xd2b5, 0x52b5, 0xcab5, 0x4ab5, 0x2ab5, 0xaab5, - 0xccd5, 0x4cd5, 0x2cd5, 0xacd5, 0x34d5, 0xb4d5, 0xd4d5, 0x54d5, - 0x32d5, 0xb2d5, 0xd2d5, 0x52d5, 0xcad5, 0x4ad5, 0x2ad5, 0xaad5, - 0x3355, 0xb355, 0xd355, 0x5355, 0xcb55, 0x4b55, 0x2b55, 0xab55, - 0xcd55, 0x4d55, 0x2d55, 0xad55, 0x3555, 0xb555, 0xd555, 0x5555, + 0x3333, 0xb333, 0xd333, 0x5333, 0xcb33, 0x4b33, 0x2b33, 0xab33, 0xcd33, + 0x4d33, 0x2d33, 0xad33, 0x3533, 0xb533, 0xd533, 0x5533, 0xccb3, 0x4cb3, + 0x2cb3, 0xacb3, 0x34b3, 0xb4b3, 0xd4b3, 0x54b3, 0x32b3, 0xb2b3, 0xd2b3, + 0x52b3, 0xcab3, 0x4ab3, 0x2ab3, 0xaab3, 0xccd3, 0x4cd3, 0x2cd3, 0xacd3, + 0x34d3, 0xb4d3, 0xd4d3, 0x54d3, 0x32d3, 0xb2d3, 0xd2d3, 0x52d3, 0xcad3, + 0x4ad3, 0x2ad3, 0xaad3, 0x3353, 0xb353, 0xd353, 0x5353, 0xcb53, 0x4b53, + 0x2b53, 0xab53, 0xcd53, 0x4d53, 0x2d53, 0xad53, 0x3553, 0xb553, 0xd553, + 0x5553, 0xcccb, 0x4ccb, 0x2ccb, 0xaccb, 0x34cb, 0xb4cb, 0xd4cb, 0x54cb, + 0x32cb, 0xb2cb, 0xd2cb, 0x52cb, 0xcacb, 0x4acb, 0x2acb, 0xaacb, 0x334b, + 0xb34b, 0xd34b, 0x534b, 0xcb4b, 0x4b4b, 0x2b4b, 0xab4b, 0xcd4b, 0x4d4b, + 0x2d4b, 0xad4b, 0x354b, 0xb54b, 0xd54b, 0x554b, 0x332b, 0xb32b, 0xd32b, + 0x532b, 0xcb2b, 0x4b2b, 0x2b2b, 0xab2b, 0xcd2b, 0x4d2b, 0x2d2b, 0xad2b, + 0x352b, 0xb52b, 0xd52b, 0x552b, 0xccab, 0x4cab, 0x2cab, 0xacab, 0x34ab, + 0xb4ab, 0xd4ab, 0x54ab, 0x32ab, 0xb2ab, 0xd2ab, 0x52ab, 0xcaab, 0x4aab, + 0x2aab, 0xaaab, 0xcccd, 0x4ccd, 0x2ccd, 0xaccd, 0x34cd, 0xb4cd, 0xd4cd, + 0x54cd, 0x32cd, 0xb2cd, 0xd2cd, 0x52cd, 0xcacd, 0x4acd, 0x2acd, 0xaacd, + 0x334d, 0xb34d, 0xd34d, 0x534d, 0xcb4d, 0x4b4d, 0x2b4d, 0xab4d, 0xcd4d, + 0x4d4d, 0x2d4d, 0xad4d, 0x354d, 0xb54d, 0xd54d, 0x554d, 0x332d, 0xb32d, + 0xd32d, 0x532d, 0xcb2d, 0x4b2d, 0x2b2d, 0xab2d, 0xcd2d, 0x4d2d, 0x2d2d, + 0xad2d, 0x352d, 0xb52d, 0xd52d, 0x552d, 0xccad, 0x4cad, 0x2cad, 0xacad, + 0x34ad, 0xb4ad, 0xd4ad, 0x54ad, 0x32ad, 0xb2ad, 0xd2ad, 0x52ad, 0xcaad, + 0x4aad, 0x2aad, 0xaaad, 0x3335, 0xb335, 0xd335, 0x5335, 0xcb35, 0x4b35, + 0x2b35, 0xab35, 0xcd35, 0x4d35, 0x2d35, 0xad35, 0x3535, 0xb535, 0xd535, + 0x5535, 0xccb5, 0x4cb5, 0x2cb5, 0xacb5, 0x34b5, 0xb4b5, 0xd4b5, 0x54b5, + 0x32b5, 0xb2b5, 0xd2b5, 0x52b5, 0xcab5, 0x4ab5, 0x2ab5, 0xaab5, 0xccd5, + 0x4cd5, 0x2cd5, 0xacd5, 0x34d5, 0xb4d5, 0xd4d5, 0x54d5, 0x32d5, 0xb2d5, + 0xd2d5, 0x52d5, 0xcad5, 0x4ad5, 0x2ad5, 0xaad5, 0x3355, 0xb355, 0xd355, + 0x5355, 0xcb55, 0x4b55, 0x2b55, 0xab55, 0xcd55, 0x4d55, 0x2d55, 0xad55, + 0x3555, 0xb555, 0xd555, 0x5555, }; -#define I2S_BUG_MAGIC (26 * 1000 * 1000) // magic number for avoiding I2S bug -#define BITS_PER_SUBFRAME 64 -#define FRAMES_PER_BLOCK 192 -#define SPDIF_BUF_SIZE (BITS_PER_SUBFRAME/8 * 2 * FRAMES_PER_BLOCK) -#define SPDIF_BUF_ARRAY_SIZE (SPDIF_BUF_SIZE / sizeof(uint32_t)) +#define I2S_BUG_MAGIC (26 * 1000 * 1000) // magic number for avoiding I2S bug +#define BITS_PER_SUBFRAME 64 +#define FRAMES_PER_BLOCK 192 +#define SPDIF_BUF_SIZE (BITS_PER_SUBFRAME / 8 * 2 * FRAMES_PER_BLOCK) +#define SPDIF_BUF_ARRAY_SIZE (SPDIF_BUF_SIZE / sizeof(uint32_t)) -#define BMC_B 0x33173333 // block start -#define BMC_M 0x331d3333 // left ch -#define BMC_W 0x331b3333 // right ch -#define BMC_MW_DIF (BMC_M ^ BMC_W) +#define BMC_B 0x33173333 // block start +#define BMC_M 0x331d3333 // left ch +#define BMC_W 0x331b3333 // right ch +#define BMC_MW_DIF (BMC_M ^ BMC_W) static uint32_t spdif_buf[SPDIF_BUF_ARRAY_SIZE]; -static uint32_t *spdif_ptr; +static uint32_t* spdif_ptr; -static void spdif_buf_init(void) -{ - // first bllock has W preamble - spdif_buf[0] = BMC_B; +static void spdif_buf_init(void) { + // first bllock has W preamble + spdif_buf[0] = BMC_B; - // all other blocks are alternating M, then W preamble - uint32_t bmc_mw = BMC_M; - for (int i = 2; i < SPDIF_BUF_ARRAY_SIZE; i += 2) - { - spdif_buf[i] = bmc_mw ^= BMC_MW_DIF; - } + // all other blocks are alternating M, then W preamble + uint32_t bmc_mw = BMC_M; + for (int i = 2; i < SPDIF_BUF_ARRAY_SIZE; i += 2) { + spdif_buf[i] = bmc_mw ^= BMC_MW_DIF; + } } -SPDIFAudioSink::SPDIFAudioSink(uint8_t spdifPin) -{ - // initialize S/PDIF buffer - spdif_buf_init(); - spdif_ptr = spdif_buf; - this->spdifPin = spdifPin; - this->setParams(44100, 16, 2); - startI2sFeed(SPDIF_BUF_SIZE * 16); +SPDIFAudioSink::SPDIFAudioSink(uint8_t spdifPin) { + // initialize S/PDIF buffer + spdif_buf_init(); + spdif_ptr = spdif_buf; + this->spdifPin = spdifPin; + this->setParams(44100, 16, 2); + startI2sFeed(SPDIF_BUF_SIZE * 16); } -bool SPDIFAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) { - if (bitDepth != 16 || channelCount != 2) // TODO support mono playback and different bit widths - return false; - int sample_rate = (int)sampleRate * 2; - int bclk = sample_rate * 64 * 2; - int mclk = (I2S_BUG_MAGIC / bclk) * bclk; +bool SPDIFAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, + uint8_t bitDepth) { + if (bitDepth != 16 || + channelCount != 2) // TODO support mono playback and different bit widths + return false; + int sample_rate = (int)sampleRate * 2; + int bclk = sample_rate * 64 * 2; + int mclk = (I2S_BUG_MAGIC / bclk) * bclk; - i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) - .sample_rate = (uint32_t) sample_rate, + .sample_rate = (uint32_t)sample_rate, #else - .sample_rate = (int) sample_rate, + .sample_rate = (int)sample_rate, #endif - .bits_per_sample = (i2s_bits_per_sample_t)(bitDepth * 2), - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = I2S_COMM_FORMAT_STAND_I2S, - .intr_alloc_flags = 0, - .dma_buf_count = 8, - .dma_buf_len = 512, - .use_apll = true, - .tx_desc_auto_clear = true, - .fixed_mclk = mclk, // avoiding I2S bug - }; - i2s_pin_config_t pin_config = { - .bck_io_num = -1, - .ws_io_num = -1, - .data_out_num = spdifPin, - .data_in_num = -1, - }; - i2s_driver_uninstall((i2s_port_t)0); - int err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, nullptr); - i2s_set_pin((i2s_port_t)0, &pin_config); - return !err; + .bits_per_sample = (i2s_bits_per_sample_t)(bitDepth * 2), + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, + .intr_alloc_flags = 0, + .dma_buf_count = 8, + .dma_buf_len = 512, + .use_apll = true, + .tx_desc_auto_clear = true, + .fixed_mclk = mclk, // avoiding I2S bug + }; + i2s_pin_config_t pin_config = { + .bck_io_num = -1, + .ws_io_num = -1, + .data_out_num = spdifPin, + .data_in_num = -1, + }; + i2s_driver_uninstall((i2s_port_t)0); + int err = i2s_driver_install((i2s_port_t)0, &i2s_config, 0, nullptr); + i2s_set_pin((i2s_port_t)0, &pin_config); + return !err; } SPDIFAudioSink::~SPDIFAudioSink() { - i2s_driver_uninstall((i2s_port_t)0); + i2s_driver_uninstall((i2s_port_t)0); } int num_frames = 0; -void SPDIFAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes) -{ - for (int i = 0; i < bytes; i += 2) - { - /** +void SPDIFAudioSink::feedPCMFrames(const uint8_t* buffer, size_t bytes) { + for (int i = 0; i < bytes; i += 2) { + /** * What is this, and why does it work? * * Rather than assemble all S/PDIF frames from scratch we want to do the @@ -171,16 +165,16 @@ void SPDIFAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes) * I did not come up with this, all credit goes to * github.com/amedes/esp_a2dp_sink_spdif */ - uint32_t lo = ((uint32_t)(bmc_convert[buffer[i]]) << 16); - uint32_t hi = (uint32_t)((int16_t)bmc_convert[buffer[i+1]]); + uint32_t lo = ((uint32_t)(bmc_convert[buffer[i]]) << 16); + uint32_t hi = (uint32_t)((int16_t)bmc_convert[buffer[i + 1]]); - *(spdif_ptr + 1) = ((lo ^ hi) << 1) >> 1; + *(spdif_ptr + 1) = ((lo ^ hi) << 1) >> 1; - spdif_ptr += 2; // advance to next audio data - - if (spdif_ptr >= &spdif_buf[SPDIF_BUF_ARRAY_SIZE]) { - feedPCMFramesInternal(spdif_buf, sizeof(spdif_buf)); - spdif_ptr = spdif_buf; - } + spdif_ptr += 2; // advance to next audio data + + if (spdif_ptr >= &spdif_buf[SPDIF_BUF_ARRAY_SIZE]) { + feedPCMFramesInternal(spdif_buf, sizeof(spdif_buf)); + spdif_ptr = spdif_buf; } + } } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/TAS5711AudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/esp/TAS5711AudioSink.cpp index ecee28da..935c5fba 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/TAS5711AudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/TAS5711AudioSink.cpp @@ -1,117 +1,107 @@ #include "TAS5711AudioSink.h" - struct tas5711_cmd_s { - uint8_t reg; - uint8_t value; + uint8_t reg; + uint8_t value; }; static const struct tas5711_cmd_s tas5711_init_sequence[] = { - { 0x00, 0x6c }, // 0x6c - 256 x mclk - { 0x04, 0x03 }, // 0x03 - 16 bit i2s - { 0x05, 0x00 }, // system control 0x00 is audio playback - { 0x06, 0x00 }, // disable mute - { 0x07, 0x50 }, // volume register - { 0xff, 0xff } + {0x00, 0x6c}, // 0x6c - 256 x mclk + {0x04, 0x03}, // 0x03 - 16 bit i2s + {0x05, 0x00}, // system control 0x00 is audio playback + {0x06, 0x00}, // disable mute + {0x07, 0x50}, // volume register + {0xff, 0xff} }; i2c_ack_type_t ACK_CHECK_EN = (i2c_ack_type_t)0x1; -TAS5711AudioSink::TAS5711AudioSink() -{ - i2s_config_t i2s_config = { +TAS5711AudioSink::TAS5711AudioSink() { + i2s_config_t i2s_config = { - .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX - .sample_rate = 44100, - .bits_per_sample = (i2s_bits_per_sample_t)16, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels - .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, - .intr_alloc_flags = 0, //Default interrupt priority - .dma_buf_count = 8, - .dma_buf_len = 512, - .use_apll = true, - .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow - .fixed_mclk = 256 * 44100 - }; + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), // Only TX + .sample_rate = 44100, + .bits_per_sample = (i2s_bits_per_sample_t)16, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels + .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB, + .intr_alloc_flags = 0, //Default interrupt priority + .dma_buf_count = 8, + .dma_buf_len = 512, + .use_apll = true, + .tx_desc_auto_clear = true, //Auto clear tx descriptor on underflow + .fixed_mclk = 256 * 44100}; + i2s_pin_config_t pin_config = { + .bck_io_num = 5, + .ws_io_num = 25, + .data_out_num = 26, + .data_in_num = -1 //Not used + }; + i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); + i2s_set_pin((i2s_port_t)0, &pin_config); - i2s_pin_config_t pin_config = { - .bck_io_num = 5, - .ws_io_num = 25, - .data_out_num = 26, - .data_in_num = -1 //Not used - }; - i2s_driver_install((i2s_port_t)0, &i2s_config, 0, NULL); - i2s_set_pin((i2s_port_t)0, &pin_config); + // configure i2c + i2c_config = { + .mode = I2C_MODE_MASTER, + .sda_io_num = 21, + .scl_io_num = 23, + .sda_pullup_en = GPIO_PULLUP_DISABLE, + .scl_pullup_en = GPIO_PULLUP_DISABLE, + }; - // configure i2c - i2c_config = { - .mode = I2C_MODE_MASTER, - .sda_io_num = 21, - .scl_io_num = 23, - .sda_pullup_en = GPIO_PULLUP_DISABLE, - .scl_pullup_en = GPIO_PULLUP_DISABLE, - }; + i2c_config.master.clk_speed = 250000; - i2c_config.master.clk_speed = 250000; + i2c_param_config(i2c_port, &i2c_config); + i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); + i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); - i2c_param_config(i2c_port, &i2c_config); - i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); - i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); + uint8_t data, addr = (0x1b); - uint8_t data, addr = (0x1b); + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (addr << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN); + i2c_master_write_byte(i2c_cmd, 00, ACK_CHECK_EN); - i2c_master_start(i2c_cmd); - i2c_master_write_byte(i2c_cmd, (addr << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN); - i2c_master_write_byte(i2c_cmd, 00, ACK_CHECK_EN); + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (addr << 1) | I2C_MASTER_READ, ACK_CHECK_EN); + i2c_master_read_byte(i2c_cmd, &data, ACK_CHECK_EN); - i2c_master_start(i2c_cmd); - i2c_master_write_byte(i2c_cmd, (addr << 1) | I2C_MASTER_READ, ACK_CHECK_EN); - i2c_master_read_byte(i2c_cmd, &data, ACK_CHECK_EN); + i2c_master_stop(i2c_cmd); + int ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(i2c_cmd); - i2c_master_stop(i2c_cmd); - int ret = i2c_master_cmd_begin(i2c_port, i2c_cmd, 50 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(i2c_cmd); + if (ret == ESP_OK) { + ESP_LOGI("RR", "Detected TAS"); + } else { + ESP_LOGI("RR", "Unable to detect dac"); + } - if (ret == ESP_OK) { - ESP_LOGI("RR", "Detected TAS"); - } - else { - ESP_LOGI("RR", "Unable to detect dac"); - } + writeReg(0x1b, 0x00); + vTaskDelay(100 / portTICK_PERIOD_MS); - writeReg(0x1b, 0x00); - vTaskDelay(100 / portTICK_PERIOD_MS); + for (int i = 0; tas5711_init_sequence[i].reg != 0xff; i++) { + writeReg(tas5711_init_sequence[i].reg, tas5711_init_sequence[i].value); + vTaskDelay(1 / portTICK_PERIOD_MS); + } - - for (int i = 0; tas5711_init_sequence[i].reg != 0xff; i++) { - writeReg(tas5711_init_sequence[i].reg, tas5711_init_sequence[i].value); - vTaskDelay(1 / portTICK_PERIOD_MS); - } - - startI2sFeed(); + startI2sFeed(); } -void TAS5711AudioSink::writeReg(uint8_t reg, uint8_t value) -{ - i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); +void TAS5711AudioSink::writeReg(uint8_t reg, uint8_t value) { + i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); - i2c_master_start(i2c_cmd); - i2c_master_write_byte(i2c_cmd, (0x1b << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN); - i2c_master_write_byte(i2c_cmd, reg, ACK_CHECK_EN); - i2c_master_write_byte(i2c_cmd, value, ACK_CHECK_EN); + i2c_master_start(i2c_cmd); + i2c_master_write_byte(i2c_cmd, (0x1b << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN); + i2c_master_write_byte(i2c_cmd, reg, ACK_CHECK_EN); + i2c_master_write_byte(i2c_cmd, value, ACK_CHECK_EN); + i2c_master_stop(i2c_cmd); + esp_err_t res = + i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_PERIOD_MS); - i2c_master_stop(i2c_cmd); - esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_PERIOD_MS); - - if (res != ESP_OK) { - ESP_LOGE("RR", "Unable to write to TAS5711"); - } - i2c_cmd_link_delete(i2c_cmd); - + if (res != ESP_OK) { + ESP_LOGE("RR", "Unable to write to TAS5711"); + } + i2c_cmd_link_delete(i2c_cmd); } -TAS5711AudioSink::~TAS5711AudioSink() -{ -} +TAS5711AudioSink::~TAS5711AudioSink() {} diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/ac101.c b/components/spotify/cspot/bell/main/audio-sinks/esp/ac101.c index c05abd86..d0fdbd0e 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/ac101.c +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/ac101.c @@ -22,16 +22,16 @@ * */ -#include -#include -#include -#include -#include -#include +#include "ac101.h" #include #include +#include +#include +#include +#include +#include +#include #include "adac.h" -#include "ac101.h" const static char TAG[] = "AC101"; @@ -42,14 +42,13 @@ const static char TAG[] = "AC101"; #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) -#define AC_ASSERT(a, format, b, ...) \ - if ((a) != 0) \ - { \ - ESP_LOGE(TAG, format, ##__VA_ARGS__); \ - return b; \ - } +#define AC_ASSERT(a, format, b, ...) \ + if ((a) != 0) { \ + ESP_LOGE(TAG, format, ##__VA_ARGS__); \ + return b; \ + } -static bool init(int i2c_port_num, int i2s_num, i2s_config_t *config); +static bool init(int i2c_port_num, int i2s_num, i2s_config_t* config); static void deinit(void); static void speaker(bool active); static void headset(bool active); @@ -71,356 +70,357 @@ static int i2c_port; /**************************************************************************************** * init */ -static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) -{ - esp_err_t res = ESP_OK; +static bool init(int i2c_port_num, int i2s_num, i2s_config_t* i2s_config) { + esp_err_t res = ESP_OK; - i2c_port = i2c_port_num; + i2c_port = i2c_port_num; - // configure i2c - i2c_config_t i2c_config = { - .mode = I2C_MODE_MASTER, - .sda_io_num = 33, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_io_num = 32, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = 250000, - }; + // configure i2c + i2c_config_t i2c_config = { + .mode = I2C_MODE_MASTER, + .sda_io_num = 33, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = 32, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 250000, + }; - i2c_param_config(i2c_port, &i2c_config); - i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); + i2c_param_config(i2c_port, &i2c_config); + i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); - res = i2c_read_reg(CHIP_AUDIO_RS); + res = i2c_read_reg(CHIP_AUDIO_RS); - if (!res) - { - ESP_LOGW(TAG, "No AC101 detected"); - i2c_driver_delete(i2c_port); - return 0; - } + if (!res) { + ESP_LOGW(TAG, "No AC101 detected"); + i2c_driver_delete(i2c_port); + return 0; + } - ESP_LOGI(TAG, "AC101 DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, i2c_config.scl_io_num); + ESP_LOGI(TAG, "AC101 DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, + i2c_config.scl_io_num); - res = i2c_write_reg(CHIP_AUDIO_RS, 0x123); - // huh? - vTaskDelay(100 / portTICK_PERIOD_MS); + res = i2c_write_reg(CHIP_AUDIO_RS, 0x123); + // huh? + vTaskDelay(100 / portTICK_PERIOD_MS); - // enable the PLL from BCLK source - i2c_write_reg(PLL_CTRL1, BIN(0000, 0001, 0100, 1111)); // F=1,M=1,PLL,INT=31 (medium) - i2c_write_reg(PLL_CTRL2, BIN(1000, 0110, 0000, 0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2; - // i2c_write_reg(PLL_CTRL2, BIN(1000,0011,1100,0000)); + // enable the PLL from BCLK source + i2c_write_reg(PLL_CTRL1, + BIN(0000, 0001, 0100, 1111)); // F=1,M=1,PLL,INT=31 (medium) + i2c_write_reg(PLL_CTRL2, BIN(1000, 0110, 0000, + 0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2; + // i2c_write_reg(PLL_CTRL2, BIN(1000,0011,1100,0000)); - // clocking system - i2c_write_reg(SYSCLK_CTRL, BIN(1010, 1010, 0000, 1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK - i2c_write_reg(MOD_CLK_ENA, BIN(1000, 0000, 0000, 1100)); // IS21, ADC, DAC - i2c_write_reg(MOD_RST_CTRL, BIN(1000, 0000, 0000, 1100)); // IS21, ADC, DAC - i2c_write_reg(I2S_SR_CTRL, BIN(0111, 0000, 0000, 0000)); // 44.1kHz + // clocking system + i2c_write_reg(SYSCLK_CTRL, BIN(1010, 1010, 0000, + 1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK + i2c_write_reg(MOD_CLK_ENA, BIN(1000, 0000, 0000, 1100)); // IS21, ADC, DAC + i2c_write_reg(MOD_RST_CTRL, BIN(1000, 0000, 0000, 1100)); // IS21, ADC, DAC + i2c_write_reg(I2S_SR_CTRL, BIN(0111, 0000, 0000, 0000)); // 44.1kHz - // analogue config - i2c_write_reg(I2S1LCK_CTRL, BIN(1000, 1000, 0101, 0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo - i2c_write_reg(I2S1_SDOUT_CTRL, BIN(1100, 0000, 0000, 0000)); // I2S1ADC (R&L) - i2c_write_reg(I2S1_SDIN_CTRL, BIN(1100, 0000, 0000, 0000)); // IS21DAC (R&L) - i2c_write_reg(I2S1_MXR_SRC, BIN(0010, 0010, 0000, 0000)); // ADCL, ADCR - i2c_write_reg(ADC_SRCBST_CTRL, BIN(0100, 0100, 0100, 0000)); // disable all boost (default) + // analogue config + i2c_write_reg(I2S1LCK_CTRL, + BIN(1000, 1000, 0101, + 0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo + i2c_write_reg(I2S1_SDOUT_CTRL, BIN(1100, 0000, 0000, 0000)); // I2S1ADC (R&L) + i2c_write_reg(I2S1_SDIN_CTRL, BIN(1100, 0000, 0000, 0000)); // IS21DAC (R&L) + i2c_write_reg(I2S1_MXR_SRC, BIN(0010, 0010, 0000, 0000)); // ADCL, ADCR + i2c_write_reg(ADC_SRCBST_CTRL, + BIN(0100, 0100, 0100, 0000)); // disable all boost (default) #if ENABLE_ADC - i2c_write_reg(ADC_SRC, BIN(0000, 0100, 0000, 1000)); // source=linein(R/L) - i2c_write_reg(ADC_DIG_CTRL, BIN(1000, 0000, 0000, 0000)); // enable digital ADC - i2c_write_reg(ADC_ANA_CTRL, BIN(1011, 1011, 0000, 0000)); // enable analogue R/L, 0dB + i2c_write_reg(ADC_SRC, BIN(0000, 0100, 0000, 1000)); // source=linein(R/L) + i2c_write_reg(ADC_DIG_CTRL, + BIN(1000, 0000, 0000, 0000)); // enable digital ADC + i2c_write_reg(ADC_ANA_CTRL, + BIN(1011, 1011, 0000, 0000)); // enable analogue R/L, 0dB #else - i2c_write_reg(ADC_SRC, BIN(0000, 0000, 0000, 0000)); // source=none - i2c_write_reg(ADC_DIG_CTRL, BIN(0000, 0000, 0000, 0000)); // disable digital ADC - i2c_write_reg(ADC_ANA_CTRL, BIN(0011, 0011, 0000, 0000)); // disable analogue R/L, 0dB + i2c_write_reg(ADC_SRC, BIN(0000, 0000, 0000, 0000)); // source=none + i2c_write_reg(ADC_DIG_CTRL, + BIN(0000, 0000, 0000, 0000)); // disable digital ADC + i2c_write_reg(ADC_ANA_CTRL, + BIN(0011, 0011, 0000, 0000)); // disable analogue R/L, 0dB #endif - //Path Configuration - i2c_write_reg(DAC_MXR_SRC, BIN(1000, 1000, 0000, 0000)); // DAC from I2S - i2c_write_reg(DAC_DIG_CTRL, BIN(1000, 0000, 0000, 0000)); // enable DAC - i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111, 0000, 0000, 0000)); // enable DAC/Analogue (see note on offset removal and PA) - i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111, 1111, 0000, 0000)); // this toggle is needed for headphone PA offset + //Path Configuration + i2c_write_reg(DAC_MXR_SRC, BIN(1000, 1000, 0000, 0000)); // DAC from I2S + i2c_write_reg(DAC_DIG_CTRL, BIN(1000, 0000, 0000, 0000)); // enable DAC + i2c_write_reg( + OMIXER_DACA_CTRL, + BIN(1111, 0000, 0000, + 0000)); // enable DAC/Analogue (see note on offset removal and PA) + i2c_write_reg(OMIXER_DACA_CTRL, + BIN(1111, 1111, 0000, + 0000)); // this toggle is needed for headphone PA offset #if ENABLE_ADC - i2c_write_reg(OMIXER_SR, BIN(0000, 0001, 0000, 0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?) + i2c_write_reg( + OMIXER_SR, + BIN(0000, 0001, 0000, + 0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?) #else - i2c_write_reg(OMIXER_SR, BIN(0000, 0101, 0000, 1010)); // source=DAC(R/L) and LINEIN(R/L) + i2c_write_reg(OMIXER_SR, BIN(0000, 0101, 0000, + 1010)); // source=DAC(R/L) and LINEIN(R/L) #endif - // configure I2S pins & install driver - i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t){.bck_io_num = 27, .ws_io_num = 26, .data_out_num = 25, .data_in_num = -1}; - res |= i2s_driver_install(i2s_num, i2s_config, 0, NULL); - res |= i2s_set_pin(i2s_num, &i2s_pin_config); + // configure I2S pins & install driver + i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t){ + .bck_io_num = 27, .ws_io_num = 26, .data_out_num = 25, .data_in_num = -1}; + res |= i2s_driver_install(i2s_num, i2s_config, 0, NULL); + res |= i2s_set_pin(i2s_num, &i2s_pin_config); - // enable earphone & speaker - i2c_write_reg(SPKOUT_CTRL, 0x0220); - i2c_write_reg(HPOUT_CTRL, 0xf801); + // enable earphone & speaker + i2c_write_reg(SPKOUT_CTRL, 0x0220); + i2c_write_reg(HPOUT_CTRL, 0xf801); - // set gain for speaker and earphone - ac101_set_spk_volume(70); - ac101_set_earph_volume(70); + // set gain for speaker and earphone + ac101_set_spk_volume(70); + ac101_set_earph_volume(70); - ESP_LOGI(TAG, "DAC using I2S bck:%d, ws:%d, do:%d", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num); + ESP_LOGI(TAG, "DAC using I2S bck:%d, ws:%d, do:%d", i2s_pin_config.bck_io_num, + i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num); - return (res == ESP_OK); + return (res == ESP_OK); } /**************************************************************************************** * init */ -static void deinit(void) -{ - i2c_driver_delete(i2c_port); +static void deinit(void) { + i2c_driver_delete(i2c_port); } /**************************************************************************************** * change volume */ -static void volume(unsigned left, unsigned right) -{ - ac101_set_earph_volume(left); - // nothing at that point, volume is handled by backend +static void volume(unsigned left, unsigned right) { + ac101_set_earph_volume(left); + // nothing at that point, volume is handled by backend } /**************************************************************************************** * power */ -static void power(adac_power_e mode) -{ - switch (mode) - { - case ADAC_STANDBY: - case ADAC_OFF: - ac101_stop(); - break; - case ADAC_ON: - ac101_start(AC_MODULE_DAC); - break; - default: - ESP_LOGW(TAG, "unknown power command"); - break; - } +static void power(adac_power_e mode) { + switch (mode) { + case ADAC_STANDBY: + case ADAC_OFF: + ac101_stop(); + break; + case ADAC_ON: + ac101_start(AC_MODULE_DAC); + break; + default: + ESP_LOGW(TAG, "unknown power command"); + break; + } } /**************************************************************************************** * speaker */ -static void speaker(bool active) -{ - uint16_t value = i2c_read_reg(SPKOUT_CTRL); - if (active) - i2c_write_reg(SPKOUT_CTRL, value | SPKOUT_EN); - else - i2c_write_reg(SPKOUT_CTRL, value & ~SPKOUT_EN); +static void speaker(bool active) { + uint16_t value = i2c_read_reg(SPKOUT_CTRL); + if (active) + i2c_write_reg(SPKOUT_CTRL, value | SPKOUT_EN); + else + i2c_write_reg(SPKOUT_CTRL, value & ~SPKOUT_EN); } /**************************************************************************************** * headset */ -static void headset(bool active) -{ - // there might be aneed to toggle OMIXER_DACA_CTRL 11:8, not sure - uint16_t value = i2c_read_reg(HPOUT_CTRL); - if (active) - i2c_write_reg(HPOUT_CTRL, value | EAROUT_EN); - else - i2c_write_reg(HPOUT_CTRL, value & ~EAROUT_EN); +static void headset(bool active) { + // there might be aneed to toggle OMIXER_DACA_CTRL 11:8, not sure + uint16_t value = i2c_read_reg(HPOUT_CTRL); + if (active) + i2c_write_reg(HPOUT_CTRL, value | EAROUT_EN); + else + i2c_write_reg(HPOUT_CTRL, value & ~EAROUT_EN); } /**************************************************************************************** * */ -static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val) -{ - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - esp_err_t ret = 0; - uint8_t send_buff[4]; - send_buff[0] = (AC101_ADDR << 1); - send_buff[1] = reg; - send_buff[2] = (val >> 8) & 0xff; - send_buff[3] = val & 0xff; - ret |= i2c_master_start(cmd); - ret |= i2c_master_write(cmd, send_buff, 4, ACK_CHECK_EN); - ret |= i2c_master_stop(cmd); - ret |= i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); - return ret; +static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + esp_err_t ret = 0; + uint8_t send_buff[4]; + send_buff[0] = (AC101_ADDR << 1); + send_buff[1] = reg; + send_buff[2] = (val >> 8) & 0xff; + send_buff[3] = val & 0xff; + ret |= i2c_master_start(cmd); + ret |= i2c_master_write(cmd, send_buff, 4, ACK_CHECK_EN); + ret |= i2c_master_stop(cmd); + ret |= i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + return ret; } /**************************************************************************************** * */ -static uint16_t i2c_read_reg(uint8_t reg) -{ - uint8_t data[2] = {0}; +static uint16_t i2c_read_reg(uint8_t reg) { + uint8_t data[2] = {0}; - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (AC101_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); - i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (AC101_ADDR << 1) | READ_BIT, ACK_CHECK_EN); //check or not - i2c_master_read(cmd, data, 2, ACK_VAL); - i2c_master_stop(cmd); - i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (AC101_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_write_byte(cmd, reg, ACK_CHECK_EN); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (AC101_ADDR << 1) | READ_BIT, + ACK_CHECK_EN); //check or not + i2c_master_read(cmd, data, 2, ACK_VAL); + i2c_master_stop(cmd); + i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); - return (data[0] << 8) + data[1]; - ; + return (data[0] << 8) + data[1]; + ; } /**************************************************************************************** * */ -void set_sample_rate(int rate) -{ - if (rate == 8000) - rate = SAMPLE_RATE_8000; - else if (rate == 11025) - rate = SAMPLE_RATE_11052; - else if (rate == 12000) - rate = SAMPLE_RATE_12000; - else if (rate == 16000) - rate = SAMPLE_RATE_16000; - else if (rate == 22050) - rate = SAMPLE_RATE_22050; - else if (rate == 24000) - rate = SAMPLE_RATE_24000; - else if (rate == 32000) - rate = SAMPLE_RATE_32000; - else if (rate == 44100) - rate = SAMPLE_RATE_44100; - else if (rate == 48000) - rate = SAMPLE_RATE_48000; - else if (rate == 96000) - rate = SAMPLE_RATE_96000; - else if (rate == 192000) - rate = SAMPLE_RATE_192000; - else - { - ESP_LOGW(TAG, "Unknown sample rate %hu", rate); - rate = SAMPLE_RATE_44100; - } - i2c_write_reg(I2S_SR_CTRL, rate); +void set_sample_rate(int rate) { + if (rate == 8000) + rate = SAMPLE_RATE_8000; + else if (rate == 11025) + rate = SAMPLE_RATE_11052; + else if (rate == 12000) + rate = SAMPLE_RATE_12000; + else if (rate == 16000) + rate = SAMPLE_RATE_16000; + else if (rate == 22050) + rate = SAMPLE_RATE_22050; + else if (rate == 24000) + rate = SAMPLE_RATE_24000; + else if (rate == 32000) + rate = SAMPLE_RATE_32000; + else if (rate == 44100) + rate = SAMPLE_RATE_44100; + else if (rate == 48000) + rate = SAMPLE_RATE_48000; + else if (rate == 96000) + rate = SAMPLE_RATE_96000; + else if (rate == 192000) + rate = SAMPLE_RATE_192000; + else { + ESP_LOGW(TAG, "Unknown sample rate %hu", rate); + rate = SAMPLE_RATE_44100; + } + i2c_write_reg(I2S_SR_CTRL, rate); } /**************************************************************************************** * Get normalized (0..100) speaker volume */ -static int ac101_get_spk_volume(void) -{ - return ((i2c_read_reg(SPKOUT_CTRL) & 0x1f) * 100) / 0x1f; +static int ac101_get_spk_volume(void) { + return ((i2c_read_reg(SPKOUT_CTRL) & 0x1f) * 100) / 0x1f; } /**************************************************************************************** * Set normalized (0..100) volume */ -static void ac101_set_spk_volume(uint8_t volume) -{ - uint16_t value = min(volume, 100); - value = ((int)value * 0x1f) / 100; - value |= i2c_read_reg(SPKOUT_CTRL) & ~0x1f; - i2c_write_reg(SPKOUT_CTRL, value); +static void ac101_set_spk_volume(uint8_t volume) { + uint16_t value = min(volume, 100); + value = ((int)value * 0x1f) / 100; + value |= i2c_read_reg(SPKOUT_CTRL) & ~0x1f; + i2c_write_reg(SPKOUT_CTRL, value); } /**************************************************************************************** * Get normalized (0..100) earphone volume */ -static int ac101_get_earph_volume(void) -{ - return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f; +static int ac101_get_earph_volume(void) { + return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f; } /**************************************************************************************** * Set normalized (0..100) earphone volume */ -static void ac101_set_earph_volume(uint8_t volume) -{ - uint16_t value = min(volume, 255); - value = (((int)value * 0x3f) / 255) << 4; - value |= i2c_read_reg(HPOUT_CTRL) & ~(0x3f << 4); - i2c_write_reg(HPOUT_CTRL, value); +static void ac101_set_earph_volume(uint8_t volume) { + uint16_t value = min(volume, 255); + value = (((int)value * 0x3f) / 255) << 4; + value |= i2c_read_reg(HPOUT_CTRL) & ~(0x3f << 4); + i2c_write_reg(HPOUT_CTRL, value); } /**************************************************************************************** * */ -static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain, ac_output_mixer_source_t source) -{ - uint16_t regval, temp, clrbit; - regval = i2c_read_reg(OMIXER_BST1_CTRL); - switch (source) - { - case SRC_MIC1: - temp = (gain & 0x7) << 6; - clrbit = ~(0x7 << 6); - break; - case SRC_MIC2: - temp = (gain & 0x7) << 3; - clrbit = ~(0x7 << 3); - break; - case SRC_LINEIN: - temp = (gain & 0x7); - clrbit = ~0x7; - break; - default: - return; - } - regval &= clrbit; - regval |= temp; - i2c_write_reg(OMIXER_BST1_CTRL, regval); +static void ac101_set_output_mixer_gain(ac_output_mixer_gain_t gain, + ac_output_mixer_source_t source) { + uint16_t regval, temp, clrbit; + regval = i2c_read_reg(OMIXER_BST1_CTRL); + switch (source) { + case SRC_MIC1: + temp = (gain & 0x7) << 6; + clrbit = ~(0x7 << 6); + break; + case SRC_MIC2: + temp = (gain & 0x7) << 3; + clrbit = ~(0x7 << 3); + break; + case SRC_LINEIN: + temp = (gain & 0x7); + clrbit = ~0x7; + break; + default: + return; + } + regval &= clrbit; + regval |= temp; + i2c_write_reg(OMIXER_BST1_CTRL, regval); } /**************************************************************************************** * */ -static void ac101_start(ac_module_t mode) -{ - if (mode == AC_MODULE_LINE) - { - i2c_write_reg(0x51, 0x0408); - i2c_write_reg(0x40, 0x8000); - i2c_write_reg(0x50, 0x3bc0); - } - if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) - { - // I2S1_SDOUT_CTRL - // i2c_write_reg(PLL_CTRL2, 0x8120); - i2c_write_reg(0x04, 0x800c); - i2c_write_reg(0x05, 0x800c); - // res |= i2c_write_reg(0x06, 0x3000); - } - if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) - { - uint16_t value = i2c_read_reg(PLL_CTRL2); - value |= 0x8000; - i2c_write_reg(PLL_CTRL2, value); - } +static void ac101_start(ac_module_t mode) { + if (mode == AC_MODULE_LINE) { + i2c_write_reg(0x51, 0x0408); + i2c_write_reg(0x40, 0x8000); + i2c_write_reg(0x50, 0x3bc0); + } + if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || + mode == AC_MODULE_LINE) { + // I2S1_SDOUT_CTRL + // i2c_write_reg(PLL_CTRL2, 0x8120); + i2c_write_reg(0x04, 0x800c); + i2c_write_reg(0x05, 0x800c); + // res |= i2c_write_reg(0x06, 0x3000); + } + if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || + mode == AC_MODULE_LINE) { + uint16_t value = i2c_read_reg(PLL_CTRL2); + value |= 0x8000; + i2c_write_reg(PLL_CTRL2, value); + } } /**************************************************************************************** * */ -static void ac101_stop(void) -{ - uint16_t value = i2c_read_reg(PLL_CTRL2); - value &= ~0x8000; - i2c_write_reg(PLL_CTRL2, value); +static void ac101_stop(void) { + uint16_t value = i2c_read_reg(PLL_CTRL2); + value &= ~0x8000; + i2c_write_reg(PLL_CTRL2, value); } /**************************************************************************************** * */ -static void ac101_deinit(void) -{ - i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset +static void ac101_deinit(void) { + i2c_write_reg(CHIP_AUDIO_RS, 0x123); //soft reset } /**************************************************************************************** * Don't know when this one is supposed to be called */ -static void ac101_i2s_config_clock(ac_i2s_clock_t *cfg) -{ - uint16_t regval = 0; - regval = i2c_read_reg(I2S1LCK_CTRL); - regval &= 0xe03f; - regval |= (cfg->bclk_div << 9); - regval |= (cfg->lclk_div << 6); - i2c_write_reg(I2S1LCK_CTRL, regval); +static void ac101_i2s_config_clock(ac_i2s_clock_t* cfg) { + uint16_t regval = 0; + regval = i2c_read_reg(I2S1LCK_CTRL); + regval &= 0xe03f; + regval |= (cfg->bclk_div << 9); + regval |= (cfg->lclk_div << 6); + i2c_write_reg(I2S1LCK_CTRL, regval); } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/esp/es8311.c b/components/spotify/cspot/bell/main/audio-sinks/esp/es8311.c index 7bf5622c..50e3415f 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/esp/es8311.c +++ b/components/spotify/cspot/bell/main/audio-sinks/esp/es8311.c @@ -22,374 +22,434 @@ * */ +#include "es8311.h" #include #include "esp_log.h" -#include "es8311.h" // #include "board.h" /* ES8311 address * 0x32:CE=1;0x30:CE=0 */ -#define ES8311_ADDR 0x32 +#define ES8311_ADDR 0x32 -#define ES7243_ADDR 0x26 +#define ES7243_ADDR 0x26 /* * to define the clock soure of MCLK */ -#define FROM_MCLK_PIN 0 -#define FROM_SCLK_PIN 1 +#define FROM_MCLK_PIN 0 +#define FROM_SCLK_PIN 1 /* * to define work mode(master or slave) */ -#define MASTER_MODE 0 -#define SLAVE_MODE 1 +#define MASTER_MODE 0 +#define SLAVE_MODE 1 /* * to define serial digital audio format */ -#define I2S_FMT 0 -#define LEFT_JUSTIFIED_FMT 1 -#define DPS_PCM_A_FMT 2 -#define DPS_PCM_B_FMT 3 +#define I2S_FMT 0 +#define LEFT_JUSTIFIED_FMT 1 +#define DPS_PCM_A_FMT 2 +#define DPS_PCM_B_FMT 3 /* * to define resolution of PCM interface */ -#define LENGTH_16BIT 0 -#define LENGTH_24BIT 1 -#define LENGTH_32BIT 2 +#define LENGTH_16BIT 0 +#define LENGTH_24BIT 1 +#define LENGTH_32BIT 2 /* * codec private data */ -struct es8311_private { - bool dmic_enable; - bool mclkinv; - bool sclkinv; - uint8_t master_slave_mode; - uint8_t pcm_format; - uint8_t pcm_resolution; - uint8_t mclk_src; +struct es8311_private { + bool dmic_enable; + bool mclkinv; + bool sclkinv; + uint8_t master_slave_mode; + uint8_t pcm_format; + uint8_t pcm_resolution; + uint8_t mclk_src; }; -static struct es8311_private *es8311_priv; +static struct es8311_private* es8311_priv; /* * Clock coefficient structer */ struct _coeff_div { - uint32_t mclk; /* mclk frequency */ - uint32_t rate; /* sample rate */ - uint8_t prediv; /* the pre divider with range from 1 to 8 */ - uint8_t premulti; /* the pre multiplier with x1, x2, x4 and x8 selection */ - uint8_t adcdiv; /* adcclk divider */ - uint8_t dacdiv; /* dacclk divider */ - uint8_t fsmode; /* double speed or single speed, =0, ss, =1, ds */ - uint8_t lrck_h; /* adclrck divider and daclrck divider */ - uint8_t lrck_l; - uint8_t bclkdiv; /* sclk divider */ - uint8_t adcosr; /* adc osr */ - uint8_t dacosr; /* dac osr */ + uint32_t mclk; /* mclk frequency */ + uint32_t rate; /* sample rate */ + uint8_t prediv; /* the pre divider with range from 1 to 8 */ + uint8_t premulti; /* the pre multiplier with x1, x2, x4 and x8 selection */ + uint8_t adcdiv; /* adcclk divider */ + uint8_t dacdiv; /* dacclk divider */ + uint8_t fsmode; /* double speed or single speed, =0, ss, =1, ds */ + uint8_t lrck_h; /* adclrck divider and daclrck divider */ + uint8_t lrck_l; + uint8_t bclkdiv; /* sclk divider */ + uint8_t adcosr; /* adc osr */ + uint8_t dacosr; /* dac osr */ }; /* codec hifi mclk clock divider coefficients */ static const struct _coeff_div coeff_div[] = { //mclk rate prediv mult adcdiv dacdiv fsmode lrch lrcl bckdiv osr /* 8k */ - {12288000, 8000 , 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 8000 , 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10, 0x10}, - {16384000, 8000 , 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 8000 , 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 8000 , 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {4096000 , 8000 , 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2048000 , 8000 , 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 8000 , 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1024000 , 8000 , 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {12288000, 8000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {18432000, 8000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10, + 0x10}, + {16384000, 8000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {8192000, 8000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {6144000, 8000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {4096000, 8000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {3072000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {2048000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {1536000, 8000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {1024000, 8000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, /* 11.025k */ - {11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {5644800, 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {2822400, 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1411200, 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 12k */ - {12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {6144000, 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {3072000, 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1536000, 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 16k */ - {12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10}, - {16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {4096000 , 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2048000 , 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1024000 , 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, + 0x10}, + {16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {8192000, 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {6144000, 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {4096000, 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {3072000, 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {2048000, 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1536000, 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1024000, 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 22.05k */ - {11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {5644800, 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {2822400, 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1411200, 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 24k */ - {12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {6144000, 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {3072000, 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1536000, 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 32k */ - {12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, 0x10}, - {16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {4096000 , 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2048000 , 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, - {1024000 , 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10, + 0x10}, + {16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {8192000, 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {6144000, 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {4096000, 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {3072000, 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {2048000, 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1536000, 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, + 0x10}, + {1024000, 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 44.1k */ - {11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {5644800, 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {2822400, 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1411200, 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 48k */ - {12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, + {12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {6144000, 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {3072000, 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1536000, 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, /* 64k */ - {12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, - {16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {8192000 , 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, - {4096000 , 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, 0x10}, - {2048000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, 0x18}, - {1024000 , 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, + {12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, + 0x10}, + {16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {8192000, 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {6144000, 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, + 0x10}, + {4096000, 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {3072000, 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10, + 0x10}, + {2048000, 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1536000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18, + 0x18}, + {1024000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, + 0x10}, /* 88.2k */ - {11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {5644800 , 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {2822400 , 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1411200 , 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, + {11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {5644800, 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {2822400, 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1411200, 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, + 0x10}, /* 96k */ - {12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {6144000 , 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {3072000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, 0x10}, - {1536000 , 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, 0x10}, + {12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {6144000, 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {3072000, 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10, + 0x10}, + {1536000, 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10, + 0x10}, }; -static char *TAG = "DRV8311"; +static char* TAG = "DRV8311"; -#define ES_ASSERT(a, format, b, ...) \ - if ((a) != 0) { \ - ESP_LOGE(TAG, format, ##__VA_ARGS__); \ - return b;\ - } +#define ES_ASSERT(a, format, b, ...) \ + if ((a) != 0) { \ + ESP_LOGE(TAG, format, ##__VA_ARGS__); \ + return b; \ + } -static int Es8311WriteReg(uint8_t regAdd, uint8_t data) -{ - int res = 0; - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - res |= i2c_master_start(cmd); - res |= i2c_master_write_byte(cmd, ES8311_ADDR, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_write_byte(cmd, data, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_stop(cmd); - res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); - ES_ASSERT(res, "Es8311 Write Reg error", -1); - return res; +static int Es8311WriteReg(uint8_t regAdd, uint8_t data) { + int res = 0; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + res |= i2c_master_start(cmd); + res |= i2c_master_write_byte(cmd, ES8311_ADDR, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_write_byte(cmd, data, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_stop(cmd); + res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + ES_ASSERT(res, "Es8311 Write Reg error", -1); + return res; } -int Es8311ReadReg(uint8_t regAdd) -{ - uint8_t data; - int res = 0; - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); +int Es8311ReadReg(uint8_t regAdd) { + uint8_t data; + int res = 0; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - res |= i2c_master_start(cmd); - res |= i2c_master_write_byte(cmd, ES8311_ADDR, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_stop(cmd); - res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); + res |= i2c_master_start(cmd); + res |= i2c_master_write_byte(cmd, ES8311_ADDR, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_stop(cmd); + res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); - cmd = i2c_cmd_link_create(); - res |= i2c_master_start(cmd); - res |= i2c_master_write_byte(cmd, ES8311_ADDR | 0x01, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_read_byte(cmd, &data, 0x01 /*NACK_VAL*/); - res |= i2c_master_stop(cmd); - res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); + cmd = i2c_cmd_link_create(); + res |= i2c_master_start(cmd); + res |= i2c_master_write_byte(cmd, ES8311_ADDR | 0x01, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_read_byte(cmd, &data, 0x01 /*NACK_VAL*/); + res |= i2c_master_stop(cmd); + res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); - ES_ASSERT(res, "Es8311 Read Reg error", -1); - return (int)data; + ES_ASSERT(res, "Es8311 Read Reg error", -1); + return (int)data; } -static int Es7243WriteReg(uint8_t regAdd, uint8_t data) -{ - int res = 0; - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - res |= i2c_master_start(cmd); - res |= i2c_master_write_byte(cmd, ES7243_ADDR, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_write_byte(cmd, data, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_stop(cmd); - res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); - ES_ASSERT(res, "Es7243 Write Reg error", -1); - return res; +static int Es7243WriteReg(uint8_t regAdd, uint8_t data) { + int res = 0; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + res |= i2c_master_start(cmd); + res |= i2c_master_write_byte(cmd, ES7243_ADDR, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_write_byte(cmd, data, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_stop(cmd); + res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + ES_ASSERT(res, "Es7243 Write Reg error", -1); + return res; } +int Es7243ReadReg(uint8_t regAdd) { + uint8_t data; + int res = 0; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); -int Es7243ReadReg(uint8_t regAdd) -{ - uint8_t data; - int res = 0; - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + res |= i2c_master_start(cmd); + res |= i2c_master_write_byte(cmd, ES7243_ADDR, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_stop(cmd); + res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); - res |= i2c_master_start(cmd); - res |= i2c_master_write_byte(cmd, ES7243_ADDR, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_write_byte(cmd, regAdd, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_stop(cmd); - res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); + cmd = i2c_cmd_link_create(); + res |= i2c_master_start(cmd); + res |= i2c_master_write_byte(cmd, ES7243_ADDR | 0x01, 1 /*ACK_CHECK_EN*/); + res |= i2c_master_read_byte(cmd, &data, 0x01 /*NACK_VAL*/); + res |= i2c_master_stop(cmd); + res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); - cmd = i2c_cmd_link_create(); - res |= i2c_master_start(cmd); - res |= i2c_master_write_byte(cmd, ES7243_ADDR | 0x01, 1 /*ACK_CHECK_EN*/); - res |= i2c_master_read_byte(cmd, &data, 0x01 /*NACK_VAL*/); - res |= i2c_master_stop(cmd); - res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); - - ES_ASSERT(res, "Es7243 Read Reg error", -1); - return (int)data; + ES_ASSERT(res, "Es7243 Read Reg error", -1); + return (int)data; } -esp_err_t Es7243Init(void) -{ - esp_err_t ret = ESP_OK; - ret |= Es7243WriteReg(0x00, 0x01); - ret |= Es7243WriteReg(0x06, 0x00); - ret |= Es7243WriteReg(0x05, 0x1B); - ret |= Es7243WriteReg(0x01, 0x0C); - ret |= Es7243WriteReg(0x08, 0x43); - ret |= Es7243WriteReg(0x05, 0x13); - if (ret) { - ESP_LOGE(TAG, "Es7243 initialize failed!"); - return ESP_FAIL; - } - return ret; +esp_err_t Es7243Init(void) { + esp_err_t ret = ESP_OK; + ret |= Es7243WriteReg(0x00, 0x01); + ret |= Es7243WriteReg(0x06, 0x00); + ret |= Es7243WriteReg(0x05, 0x1B); + ret |= Es7243WriteReg(0x01, 0x0C); + ret |= Es7243WriteReg(0x08, 0x43); + ret |= Es7243WriteReg(0x05, 0x13); + if (ret) { + ESP_LOGE(TAG, "Es7243 initialize failed!"); + return ESP_FAIL; + } + return ret; } -static int I2cInit(i2c_config_t *conf, int i2cMasterPort) -{ - int res; - res = i2c_param_config(i2cMasterPort, conf); - res |= i2c_driver_install(i2cMasterPort, conf->mode, 0, 0, 0); - ES_ASSERT(res, "I2cInit error", -1); - return res; +static int I2cInit(i2c_config_t* conf, int i2cMasterPort) { + int res; + res = i2c_param_config(i2cMasterPort, conf); + res |= i2c_driver_install(i2cMasterPort, conf->mode, 0, 0, 0); + ES_ASSERT(res, "I2cInit error", -1); + return res; } /* * look for the coefficient in coeff_div[] table */ -static int get_coeff(uint32_t mclk, uint32_t rate) -{ - for (int i = 0; i < (sizeof(coeff_div) / sizeof(coeff_div[0])); i++) { - if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) - return i; - } - return -1; +static int get_coeff(uint32_t mclk, uint32_t rate) { + for (int i = 0; i < (sizeof(coeff_div) / sizeof(coeff_div[0])); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + return -1; } /* * set es8311 clock parameter and PCM/I2S interface */ -static void es8311_pcm_hw_params(uint32_t mclk, uint32_t lrck) -{ - int coeff; - uint8_t regv, datmp; - ESP_LOGI(TAG, "Enter into es8311_pcm_hw_params()\n"); - coeff = get_coeff(mclk, lrck); - if (coeff < 0) { - ESP_LOGE(TAG, "Unable to configure sample rate %dHz with %dHz MCLK\n", lrck, mclk); - return; - } +static void es8311_pcm_hw_params(uint32_t mclk, uint32_t lrck) { + int coeff; + uint8_t regv, datmp; + ESP_LOGI(TAG, "Enter into es8311_pcm_hw_params()\n"); + coeff = get_coeff(mclk, lrck); + if (coeff < 0) { + ESP_LOGE(TAG, "Unable to configure sample rate %dHz with %dHz MCLK\n", lrck, + mclk); + return; + } - /* + /* * set clock parammeters */ - if (coeff >= 0) { - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG02) & 0x07; - regv |= (coeff_div[coeff].prediv - 1) << 5; + if (coeff >= 0) { + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG02) & 0x07; + regv |= (coeff_div[coeff].prediv - 1) << 5; + datmp = 0; + switch (coeff_div[coeff].premulti) { + case 1: datmp = 0; - switch (coeff_div[coeff].premulti) { - case 1: - datmp = 0; - break; - case 2: - datmp = 1; - break; - case 4: - datmp = 2; - break; - case 8: - datmp = 3; - break; - default: - break; - } -#if CONFIG_ESP32_KORVO_V1_1_BOARD + break; + case 2: + datmp = 1; + break; + case 4: + datmp = 2; + break; + case 8: datmp = 3; -#endif - regv |= (datmp) << 3; - Es8311WriteReg(ES8311_CLK_MANAGER_REG02, regv); - - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG05) & 0x00; - regv |= (coeff_div[coeff].adcdiv - 1) << 4; - regv |= (coeff_div[coeff].dacdiv - 1) << 0; - Es8311WriteReg(ES8311_CLK_MANAGER_REG05, regv); - - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG03) & 0x80; - regv |= coeff_div[coeff].fsmode << 6; - regv |= coeff_div[coeff].adcosr << 0; - Es8311WriteReg(ES8311_CLK_MANAGER_REG03, regv); - - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG04) & 0x80; - regv |= coeff_div[coeff].dacosr << 0; - Es8311WriteReg(ES8311_CLK_MANAGER_REG04, regv); - - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG07) & 0xC0; - regv |= coeff_div[coeff].lrck_h << 0; - Es8311WriteReg(ES8311_CLK_MANAGER_REG07, regv); - - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG08) & 0x00; - regv |= coeff_div[coeff].lrck_l << 0; - Es8311WriteReg(ES8311_CLK_MANAGER_REG08, regv); - - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06) & 0xE0; - if (coeff_div[coeff].bclkdiv < 19) { - regv |= (coeff_div[coeff].bclkdiv - 1) << 0; - } else { - regv |= (coeff_div[coeff].bclkdiv) << 0; - } - Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv); + break; + default: + break; } +#if CONFIG_ESP32_KORVO_V1_1_BOARD + datmp = 3; +#endif + regv |= (datmp) << 3; + Es8311WriteReg(ES8311_CLK_MANAGER_REG02, regv); + + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG05) & 0x00; + regv |= (coeff_div[coeff].adcdiv - 1) << 4; + regv |= (coeff_div[coeff].dacdiv - 1) << 0; + Es8311WriteReg(ES8311_CLK_MANAGER_REG05, regv); + + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG03) & 0x80; + regv |= coeff_div[coeff].fsmode << 6; + regv |= coeff_div[coeff].adcosr << 0; + Es8311WriteReg(ES8311_CLK_MANAGER_REG03, regv); + + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG04) & 0x80; + regv |= coeff_div[coeff].dacosr << 0; + Es8311WriteReg(ES8311_CLK_MANAGER_REG04, regv); + + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG07) & 0xC0; + regv |= coeff_div[coeff].lrck_h << 0; + Es8311WriteReg(ES8311_CLK_MANAGER_REG07, regv); + + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG08) & 0x00; + regv |= coeff_div[coeff].lrck_l << 0; + Es8311WriteReg(ES8311_CLK_MANAGER_REG08, regv); + + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06) & 0xE0; + if (coeff_div[coeff].bclkdiv < 19) { + regv |= (coeff_div[coeff].bclkdiv - 1) << 0; + } else { + regv |= (coeff_div[coeff].bclkdiv) << 0; + } + Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv); + } } /* * set data and clock in tri-state mode @@ -412,20 +472,19 @@ static void es8311_pcm_hw_params(uint32_t mclk, uint32_t lrck) * if mute = 0, dac un-mute * if mute = 1, dac mute */ -static void es8311_mute(int mute) -{ - uint8_t regv; - ESP_LOGI(TAG, "Enter into es8311_mute(), mute = %d\n", mute); - regv = Es8311ReadReg(ES8311_DAC_REG31) & 0x9f; - if (mute) { - Es8311WriteReg(ES8311_SYSTEM_REG12, 0x02); - Es8311WriteReg(ES8311_DAC_REG31, regv | 0x60); - Es8311WriteReg(ES8311_DAC_REG32, 0x00); - Es8311WriteReg(ES8311_DAC_REG37, 0x08); - } else { - Es8311WriteReg(ES8311_DAC_REG31, regv); - Es8311WriteReg(ES8311_SYSTEM_REG12, 0x00); - } +static void es8311_mute(int mute) { + uint8_t regv; + ESP_LOGI(TAG, "Enter into es8311_mute(), mute = %d\n", mute); + regv = Es8311ReadReg(ES8311_DAC_REG31) & 0x9f; + if (mute) { + Es8311WriteReg(ES8311_SYSTEM_REG12, 0x02); + Es8311WriteReg(ES8311_DAC_REG31, regv | 0x60); + Es8311WriteReg(ES8311_DAC_REG32, 0x00); + Es8311WriteReg(ES8311_DAC_REG37, 0x08); + } else { + Es8311WriteReg(ES8311_DAC_REG31, regv); + Es8311WriteReg(ES8311_SYSTEM_REG12, 0x00); + } } /* * set es8311 into suspend mode @@ -450,135 +509,133 @@ static void es8311_mute(int mute) /* * initialize es8311 codec */ -static void es8311_init(uint32_t mclk_freq, uint32_t lrck_freq) -{ - int regv; - Es8311WriteReg(ES8311_GP_REG45, 0x00); - Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x30); - Es8311WriteReg(ES8311_CLK_MANAGER_REG02, 0x00); - Es8311WriteReg(ES8311_CLK_MANAGER_REG03, 0x10); - Es8311WriteReg(ES8311_ADC_REG16, 0x24); - Es8311WriteReg(ES8311_CLK_MANAGER_REG04, 0x10); - Es8311WriteReg(ES8311_CLK_MANAGER_REG05, 0x00); - Es8311WriteReg(ES8311_SYSTEM_REG0B, 0x00); - Es8311WriteReg(ES8311_SYSTEM_REG0C, 0x00); - Es8311WriteReg(ES8311_SYSTEM_REG10, 0x1F); - Es8311WriteReg(ES8311_SYSTEM_REG11, 0x7F); - Es8311WriteReg(ES8311_RESET_REG00, 0x80); - /* +static void es8311_init(uint32_t mclk_freq, uint32_t lrck_freq) { + int regv; + Es8311WriteReg(ES8311_GP_REG45, 0x00); + Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x30); + Es8311WriteReg(ES8311_CLK_MANAGER_REG02, 0x00); + Es8311WriteReg(ES8311_CLK_MANAGER_REG03, 0x10); + Es8311WriteReg(ES8311_ADC_REG16, 0x24); + Es8311WriteReg(ES8311_CLK_MANAGER_REG04, 0x10); + Es8311WriteReg(ES8311_CLK_MANAGER_REG05, 0x00); + Es8311WriteReg(ES8311_SYSTEM_REG0B, 0x00); + Es8311WriteReg(ES8311_SYSTEM_REG0C, 0x00); + Es8311WriteReg(ES8311_SYSTEM_REG10, 0x1F); + Es8311WriteReg(ES8311_SYSTEM_REG11, 0x7F); + Es8311WriteReg(ES8311_RESET_REG00, 0x80); + /* * Set Codec into Master or Slave mode */ - regv = Es8311ReadReg(ES8311_RESET_REG00); - /* set master/slave audio interface */ - switch (es8311_priv->master_slave_mode) { - case MASTER_MODE: /* MASTER MODE */ - ESP_LOGI(TAG, "ES8311 in Master mode\n"); - regv |= 0x40; - break; - case SLAVE_MODE: /* SLAVE MODE */ - ESP_LOGI(TAG, "ES8311 in Slave mode\n"); - regv &= 0xBF; - break; - default: - regv &= 0xBF; - } - Es8311WriteReg(ES8311_RESET_REG00, regv); - Es8311WriteReg(ES8311_SYSTEM_REG0D, 0x01); - Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x3F); - /* + regv = Es8311ReadReg(ES8311_RESET_REG00); + /* set master/slave audio interface */ + switch (es8311_priv->master_slave_mode) { + case MASTER_MODE: /* MASTER MODE */ + ESP_LOGI(TAG, "ES8311 in Master mode\n"); + regv |= 0x40; + break; + case SLAVE_MODE: /* SLAVE MODE */ + ESP_LOGI(TAG, "ES8311 in Slave mode\n"); + regv &= 0xBF; + break; + default: + regv &= 0xBF; + } + Es8311WriteReg(ES8311_RESET_REG00, regv); + Es8311WriteReg(ES8311_SYSTEM_REG0D, 0x01); + Es8311WriteReg(ES8311_CLK_MANAGER_REG01, 0x3F); + /* * select clock source for internal mclk */ - switch (es8311_priv->mclk_src) { - case FROM_MCLK_PIN: - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); - regv &= 0x7F; - Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); - break; - case FROM_SCLK_PIN: - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); - regv |= 0x80; - Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); - break; - default: - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); - regv &= 0x7F; - Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); - break; - } - es8311_pcm_hw_params(lrck_freq * 256, lrck_freq); + switch (es8311_priv->mclk_src) { + case FROM_MCLK_PIN: + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); + regv &= 0x7F; + Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); + break; + case FROM_SCLK_PIN: + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); + regv |= 0x80; + Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); + break; + default: + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); + regv &= 0x7F; + Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); + break; + } + es8311_pcm_hw_params(lrck_freq * 256, lrck_freq); - /* + /* * mclk inverted or not */ - if (es8311_priv->mclkinv == true) { - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); - regv |= 0x40; - Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); - } else { - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); - regv &= ~(0x40); - Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); - } - /* + if (es8311_priv->mclkinv == true) { + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); + regv |= 0x40; + Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); + } else { + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG01); + regv &= ~(0x40); + Es8311WriteReg(ES8311_CLK_MANAGER_REG01, regv); + } + /* * sclk inverted or not */ - if (es8311_priv->sclkinv == true) { - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06); - regv |= 0x20; - Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv); - } else { - regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06); - regv &= ~(0x20); - Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv); - } - Es8311WriteReg(ES8311_SYSTEM_REG14, 0x1A); - /* + if (es8311_priv->sclkinv == true) { + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06); + regv |= 0x20; + Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv); + } else { + regv = Es8311ReadReg(ES8311_CLK_MANAGER_REG06); + regv &= ~(0x20); + Es8311WriteReg(ES8311_CLK_MANAGER_REG06, regv); + } + Es8311WriteReg(ES8311_SYSTEM_REG14, 0x1A); + /* * pdm dmic enable or disable */ - if (es8311_priv->dmic_enable == true) { - regv = Es8311ReadReg(ES8311_SYSTEM_REG14); - regv |= 0x40; - Es8311WriteReg(ES8311_SYSTEM_REG14, regv); - } else { - regv = Es8311ReadReg(ES8311_SYSTEM_REG14); - regv &= ~(0x40); - Es8311WriteReg(ES8311_SYSTEM_REG14, regv); - } + if (es8311_priv->dmic_enable == true) { + regv = Es8311ReadReg(ES8311_SYSTEM_REG14); + regv |= 0x40; + Es8311WriteReg(ES8311_SYSTEM_REG14, regv); + } else { + regv = Es8311ReadReg(ES8311_SYSTEM_REG14); + regv &= ~(0x40); + Es8311WriteReg(ES8311_SYSTEM_REG14, regv); + } - Es8311WriteReg(ES8311_SYSTEM_REG13, 0x10); - Es8311WriteReg(ES8311_SYSTEM_REG0E, 0x02); - Es8311WriteReg(ES8311_ADC_REG15, 0x40); - Es8311WriteReg(ES8311_ADC_REG1B, 0x0A); - Es8311WriteReg(ES8311_ADC_REG1C, 0x6A); - Es8311WriteReg(ES8311_DAC_REG37, 0x48); - Es8311WriteReg(ES8311_GPIO_REG44, 0x08); - Es8311WriteReg(ES8311_DAC_REG32, 0xBF); + Es8311WriteReg(ES8311_SYSTEM_REG13, 0x10); + Es8311WriteReg(ES8311_SYSTEM_REG0E, 0x02); + Es8311WriteReg(ES8311_ADC_REG15, 0x40); + Es8311WriteReg(ES8311_ADC_REG1B, 0x0A); + Es8311WriteReg(ES8311_ADC_REG1C, 0x6A); + Es8311WriteReg(ES8311_DAC_REG37, 0x48); + Es8311WriteReg(ES8311_GPIO_REG44, 0x08); + Es8311WriteReg(ES8311_DAC_REG32, 0xBF); #ifdef CONFIG_USE_ES7243 - Es7243Init(); + Es7243Init(); #endif } /* * set codec private data and initialize codec */ -void es8311_Codec_Startup(uint32_t mclk_freq, uint32_t lrck_freq) -{ - ESP_LOGI(TAG, "Enter into es8311_Codec_Startup()\n"); - es8311_priv->dmic_enable = false; - es8311_priv->mclkinv = false; - es8311_priv->sclkinv = false; - es8311_priv->pcm_format = I2S_FMT; - es8311_priv->pcm_resolution = LENGTH_16BIT; - es8311_priv->master_slave_mode = SLAVE_MODE; +void es8311_Codec_Startup(uint32_t mclk_freq, uint32_t lrck_freq) { + ESP_LOGI(TAG, "Enter into es8311_Codec_Startup()\n"); + es8311_priv->dmic_enable = false; + es8311_priv->mclkinv = false; + es8311_priv->sclkinv = false; + es8311_priv->pcm_format = I2S_FMT; + es8311_priv->pcm_resolution = LENGTH_16BIT; + es8311_priv->master_slave_mode = SLAVE_MODE; #ifdef CONFIG_ESP32_KORVO_V1_1_BOARD - es8311_priv->mclk_src = FROM_SCLK_PIN; + es8311_priv->mclk_src = FROM_SCLK_PIN; #else - es8311_priv->mclk_src = FROM_MCLK_PIN; + es8311_priv->mclk_src = FROM_MCLK_PIN; #endif - es8311_init(mclk_freq, lrck_freq); + es8311_init(mclk_freq, lrck_freq); - ESP_LOGI(TAG, "Exit es8311_Codec_Startup()\n"); + ESP_LOGI(TAG, "Exit es8311_Codec_Startup()\n"); } // static int Es8311SetAdcDacVolume(int mode, int volume, int dot) @@ -596,201 +653,186 @@ void es8311_Codec_Startup(uint32_t mclk_freq, uint32_t lrck_freq) // return res; // } -esp_err_t Es8311GetRef(bool flag) -{ - esp_err_t ret = ESP_OK; - uint8_t regv = 0; - if (flag) { - regv = Es8311ReadReg(ES8311_GPIO_REG44); - regv |= 0x50; - ret |= Es8311WriteReg(ES8311_GPIO_REG44, regv); - } else { - ret |= Es8311WriteReg(ES8311_GPIO_REG44, 0x08); - } - return ret; +esp_err_t Es8311GetRef(bool flag) { + esp_err_t ret = ESP_OK; + uint8_t regv = 0; + if (flag) { + regv = Es8311ReadReg(ES8311_GPIO_REG44); + regv |= 0x50; + ret |= Es8311WriteReg(ES8311_GPIO_REG44, regv); + } else { + ret |= Es8311WriteReg(ES8311_GPIO_REG44, 0x08); + } + return ret; } -int Es8311Init(Es8311Config *cfg) -{ - es8311_priv = calloc(1, sizeof(struct es8311_private)); - I2cInit(&cfg->i2c_cfg, cfg->i2c_port_num); // ESP32 in master mode - es8311_Codec_Startup(11289600, 44100); - return 0; +int Es8311Init(Es8311Config* cfg) { + es8311_priv = calloc(1, sizeof(struct es8311_private)); + I2cInit(&cfg->i2c_cfg, cfg->i2c_port_num); // ESP32 in master mode + es8311_Codec_Startup(11289600, 44100); + return 0; } -void Es8311Uninit() -{ - Es8311WriteReg(ES8311_RESET_REG00, 0x3f); - free(es8311_priv); - es8311_priv = NULL; +void Es8311Uninit() { + Es8311WriteReg(ES8311_RESET_REG00, 0x3f); + free(es8311_priv); + es8311_priv = NULL; } -int Es8311ConfigFmt(ESCodecModule mode, ESCodecI2SFmt fmt) -{ - int res = 0; - uint8_t regAdc = 0, regDac = 0; - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - res |= Es8311WriteReg(ES8311_ADC_REG17, 0xBF); - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - res |= Es8311WriteReg(ES8311_SYSTEM_REG12, 0x00); - } - regAdc = Es8311ReadReg(ES8311_SDPIN_REG09); - regDac = Es8311ReadReg(ES8311_SDPOUT_REG0A); - switch (fmt) { - case ES_I2S_NORMAL: - ESP_LOGI(TAG, "ES8311 in I2S Format"); - regAdc &= ~0x03; - regDac &= ~0x03; - break; - case ES_I2S_LEFT: - case ES_I2S_RIGHT: - ESP_LOGI(TAG, "ES8311 in LJ Format"); - regAdc &= ~0x03; - regAdc |= 0x01; - regDac &= ~0x03; - regDac |= 0x01; - break; - case ES_I2S_DSP: - ESP_LOGI(TAG, "ES8311 in DSP Format"); - regAdc |= 0x03; - regDac |= 0x03; - break; - default: - ESP_LOGE(TAG, "Not Supported Format"); - break; - } - res |= Es8311WriteReg(ES8311_SDPIN_REG09, regAdc); - res |= Es8311WriteReg(ES8311_SDPOUT_REG0A, regDac); - return res; +int Es8311ConfigFmt(ESCodecModule mode, ESCodecI2SFmt fmt) { + int res = 0; + uint8_t regAdc = 0, regDac = 0; + if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { + res |= Es8311WriteReg(ES8311_ADC_REG17, 0xBF); + } + if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { + res |= Es8311WriteReg(ES8311_SYSTEM_REG12, 0x00); + } + regAdc = Es8311ReadReg(ES8311_SDPIN_REG09); + regDac = Es8311ReadReg(ES8311_SDPOUT_REG0A); + switch (fmt) { + case ES_I2S_NORMAL: + ESP_LOGI(TAG, "ES8311 in I2S Format"); + regAdc &= ~0x03; + regDac &= ~0x03; + break; + case ES_I2S_LEFT: + case ES_I2S_RIGHT: + ESP_LOGI(TAG, "ES8311 in LJ Format"); + regAdc &= ~0x03; + regAdc |= 0x01; + regDac &= ~0x03; + regDac |= 0x01; + break; + case ES_I2S_DSP: + ESP_LOGI(TAG, "ES8311 in DSP Format"); + regAdc |= 0x03; + regDac |= 0x03; + break; + default: + ESP_LOGE(TAG, "Not Supported Format"); + break; + } + res |= Es8311WriteReg(ES8311_SDPIN_REG09, regAdc); + res |= Es8311WriteReg(ES8311_SDPOUT_REG0A, regDac); + return res; } -int Es8311I2sConfigClock(ESCodecI2sClock cfg) -{ - int res = 0; - return res; +int Es8311I2sConfigClock(ESCodecI2sClock cfg) { + int res = 0; + return res; } -int Es8311SetBitsPerSample(ESCodecModule mode, BitsLength bitPerSample) -{ - int res = 0; - uint8_t reg = 0; - int bits = (int)bitPerSample; +int Es8311SetBitsPerSample(ESCodecModule mode, BitsLength bitPerSample) { + int res = 0; + uint8_t reg = 0; + int bits = (int)bitPerSample; - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - reg = Es8311ReadReg(ES8311_SDPIN_REG09); - reg = reg & 0xe3; - res |= Es8311WriteReg(ES8311_SDPIN_REG09, reg | (bits << 2)); - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - reg = Es8311ReadReg(ES8311_SDPOUT_REG0A); - reg = reg & 0xe3; - res |= Es8311WriteReg(ES8311_SDPOUT_REG0A, reg | (bits << 2)); - } - return res; + if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { + reg = Es8311ReadReg(ES8311_SDPIN_REG09); + reg = reg & 0xe3; + res |= Es8311WriteReg(ES8311_SDPIN_REG09, reg | (bits << 2)); + } + if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { + reg = Es8311ReadReg(ES8311_SDPOUT_REG0A); + reg = reg & 0xe3; + res |= Es8311WriteReg(ES8311_SDPOUT_REG0A, reg | (bits << 2)); + } + return res; } -int Es8311Start(ESCodecModule mode) -{ - int res = 0; - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - res |= Es8311WriteReg(ES8311_ADC_REG17, 0xBF); - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - res |= Es8311WriteReg(ES8311_SYSTEM_REG12, Es8311ReadReg(ES8311_SYSTEM_REG12) & 0xfd); - } - return res; +int Es8311Start(ESCodecModule mode) { + int res = 0; + if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { + res |= Es8311WriteReg(ES8311_ADC_REG17, 0xBF); + } + if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { + res |= Es8311WriteReg(ES8311_SYSTEM_REG12, + Es8311ReadReg(ES8311_SYSTEM_REG12) & 0xfd); + } + return res; } -int Es8311Stop(ESCodecModule mode) -{ - int res = 0; - if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { - res |= Es8311WriteReg(ES8311_ADC_REG17, 0x00); - } - if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { - res |= Es8311WriteReg(ES8311_SYSTEM_REG12, Es8311ReadReg(ES8311_SYSTEM_REG12) | 0x02); - } - return res; +int Es8311Stop(ESCodecModule mode) { + int res = 0; + if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC) { + res |= Es8311WriteReg(ES8311_ADC_REG17, 0x00); + } + if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC) { + res |= Es8311WriteReg(ES8311_SYSTEM_REG12, + Es8311ReadReg(ES8311_SYSTEM_REG12) | 0x02); + } + return res; } -int Es8311SetVoiceVolume(int volume) -{ - int res = 0; +int Es8311SetVoiceVolume(int volume) { + int res = 0; - if (volume == 0) { - volume = 1; - } + if (volume == 0) { + volume = 1; + } - Es8311WriteReg(ES8311_DAC_REG32, volume); - return res; + Es8311WriteReg(ES8311_DAC_REG32, volume); + return res; } -int Es8311GetVoiceVolume(int *volume) -{ - int res = ESP_OK; - int regv = Es8311ReadReg(ES8311_DAC_REG32); - if (regv == ESP_FAIL) { - *volume = 0; - res = ESP_FAIL; - } else { - *volume = regv * 100 / 256; - } - ESP_LOGI(TAG, "GET: res:%d, volume:%d\n", regv, *volume); - return res; +int Es8311GetVoiceVolume(int* volume) { + int res = ESP_OK; + int regv = Es8311ReadReg(ES8311_DAC_REG32); + if (regv == ESP_FAIL) { + *volume = 0; + res = ESP_FAIL; + } else { + *volume = regv * 100 / 256; + } + ESP_LOGI(TAG, "GET: res:%d, volume:%d\n", regv, *volume); + return res; } -int Es8311SetVoiceMute(int enable) -{ - int res = 0; - ESP_LOGI(TAG, "Es8311SetVoiceMute volume:%d\n", enable); - es8311_mute(enable); - return res; +int Es8311SetVoiceMute(int enable) { + int res = 0; + ESP_LOGI(TAG, "Es8311SetVoiceMute volume:%d\n", enable); + es8311_mute(enable); + return res; } -int Es8311GetVoiceMute(int *mute) -{ - int res = -1; - uint8_t reg = 0; - res = Es8311ReadReg(ES8311_DAC_REG31); - if (res != ESP_FAIL) { - reg = (res & 0x20) >> 5; - } - *mute = reg; - return res; +int Es8311GetVoiceMute(int* mute) { + int res = -1; + uint8_t reg = 0; + res = Es8311ReadReg(ES8311_DAC_REG31); + if (res != ESP_FAIL) { + reg = (res & 0x20) >> 5; + } + *mute = reg; + return res; } -int Es8311SetMicGain(MicGain gain) -{ - int res = 0; - uint8_t gain_n = Es8311ReadReg(ES8311_ADC_REG16) & 0x07; - gain_n |= gain / 6; - res = Es8311WriteReg(ES8311_ADC_REG16, gain_n); // MIC gain scale - return res; +int Es8311SetMicGain(MicGain gain) { + int res = 0; + uint8_t gain_n = Es8311ReadReg(ES8311_ADC_REG16) & 0x07; + gain_n |= gain / 6; + res = Es8311WriteReg(ES8311_ADC_REG16, gain_n); // MIC gain scale + return res; } -int Es8311ConfigAdcInput(AdcInput input) -{ - int res = 0; - return res; +int Es8311ConfigAdcInput(AdcInput input) { + int res = 0; + return res; } -int Es8311SetAdcVolume(uint8_t adc_vol) -{ - int res = 0; - res = Es8311WriteReg(ES8311_ADC_REG17, adc_vol); // MIC ADC Volume - return res; +int Es8311SetAdcVolume(uint8_t adc_vol) { + int res = 0; + res = Es8311WriteReg(ES8311_ADC_REG17, adc_vol); // MIC ADC Volume + return res; } -int ES8311WriteReg(uint8_t regAdd, uint8_t data) -{ - return Es8311WriteReg(regAdd, data); +int ES8311WriteReg(uint8_t regAdd, uint8_t data) { + return Es8311WriteReg(regAdd, data); } -void Es8311ReadAll() -{ - for (int i = 0; i < 0x4A; i++) { - uint8_t reg = Es8311ReadReg(i); - // ets_printf("REG:%02x, %02x\n", reg, i); - } +void Es8311ReadAll() { + for (int i = 0; i < 0x4A; i++) { + uint8_t reg = Es8311ReadReg(i); + // ets_printf("REG:%02x, %02x\n", reg, i); + } } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/AudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/AudioSink.h index 96432513..65b4fd9c 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/AudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/AudioSink.h @@ -5,21 +5,23 @@ #include #include -class AudioSink -{ - public: - AudioSink() {} - virtual ~AudioSink() {} - virtual void feedPCMFrames(const uint8_t *buffer, size_t bytes) = 0; - virtual void volumeChanged(uint16_t volume) {} - // Return false if the sink doesn't support reconfiguration. - virtual bool setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) { return false; } - // Deprecated. Implement/use setParams() instead. - virtual inline bool setRate(uint16_t sampleRate) { - return setParams(sampleRate, 2, 16); - } - bool softwareVolumeControl = true; - bool usign = false; +class AudioSink { + public: + AudioSink() {} + virtual ~AudioSink() {} + virtual void feedPCMFrames(const uint8_t* buffer, size_t bytes) = 0; + virtual void volumeChanged(uint16_t volume) {} + // Return false if the sink doesn't support reconfiguration. + virtual bool setParams(uint32_t sampleRate, uint8_t channelCount, + uint8_t bitDepth) { + return false; + } + // Deprecated. Implement/use setParams() instead. + virtual inline bool setRate(uint16_t sampleRate) { + return setParams(sampleRate, 2, 16); + } + bool softwareVolumeControl = true; + bool usign = false; }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/AC101AudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/AC101AudioSink.h index 98c1c0ff..695bcf8a 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/AC101AudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/AC101AudioSink.h @@ -1,26 +1,26 @@ #ifndef AC101AUDIOSINK_H #define AC101AUDIOSINK_H -#include -#include -#include "BufferedAudioSink.h" #include #include -#include #include -#include "esp_err.h" -#include "esp_log.h" +#include +#include +#include +#include "BufferedAudioSink.h" #include "ac101.h" #include "adac.h" +#include "esp_err.h" +#include "esp_log.h" -class AC101AudioSink : public BufferedAudioSink -{ -public: - AC101AudioSink(); - ~AC101AudioSink(); - void volumeChanged(uint16_t volume); -private: - adac_s *dac; +class AC101AudioSink : public BufferedAudioSink { + public: + AC101AudioSink(); + ~AC101AudioSink(); + void volumeChanged(uint16_t volume); + + private: + adac_s* dac; }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/BufferedAudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/BufferedAudioSink.h index eb63caf9..f5dc2319 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/BufferedAudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/BufferedAudioSink.h @@ -1,25 +1,27 @@ #ifndef BUFFEREDAUDIOSINK_H #define BUFFEREDAUDIOSINK_H -#include -#include -#include "AudioSink.h" #include #include -#include #include +#include +#include +#include +#include "AudioSink.h" #include "esp_err.h" #include "esp_log.h" -class BufferedAudioSink : public AudioSink -{ -public: - void feedPCMFrames(const uint8_t *buffer, size_t bytes) override; - bool setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override; -protected: - void startI2sFeed(size_t buf_size = 4096 * 8); - void feedPCMFramesInternal(const void *pvItem, size_t xItemSize); -private: +class BufferedAudioSink : public AudioSink { + public: + void feedPCMFrames(const uint8_t* buffer, size_t bytes) override; + bool setParams(uint32_t sampleRate, uint8_t channelCount, + uint8_t bitDepth) override; + + protected: + void startI2sFeed(size_t buf_size = 4096 * 8); + void feedPCMFramesInternal(const void* pvItem, size_t xItemSize); + + private: }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8311AudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8311AudioSink.h index 697e81b7..6e756ab9 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8311AudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8311AudioSink.h @@ -1,28 +1,28 @@ #ifndef ES8311AUDIOSINK_H #define ES8311AUDIOSINK_H -#include "driver/i2s.h" -#include -#include -#include "BufferedAudioSink.h" #include #include +#include +#include +#include +#include +#include "BufferedAudioSink.h" #include "driver/gpio.h" #include "driver/i2c.h" -#include -#include +#include "driver/i2s.h" #include "esp_err.h" #include "esp_log.h" -class ES8311AudioSink : public BufferedAudioSink -{ -public: - ES8311AudioSink(); - ~ES8311AudioSink(); - void writeReg(uint8_t reg_add, uint8_t data); - void volumeChanged(uint16_t volume); - void setSampleRate(uint32_t sampleRate); -private: +class ES8311AudioSink : public BufferedAudioSink { + public: + ES8311AudioSink(); + ~ES8311AudioSink(); + void writeReg(uint8_t reg_add, uint8_t data); + void volumeChanged(uint16_t volume); + void setSampleRate(uint32_t sampleRate); + + private: }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8388AudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8388AudioSink.h index 77c917c8..92743647 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8388AudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES8388AudioSink.h @@ -1,23 +1,22 @@ #ifndef ES8388AUDIOSINK_H #define ES8388AUDIOSINK_H -#include "driver/i2s.h" #include -#include -#include -#include "BufferedAudioSink.h" +#include #include #include -#include -#include #include +#include +#include +#include +#include "BufferedAudioSink.h" +#include "driver/i2s.h" #include "esp_err.h" #include "esp_log.h" - #define ES8388_ADDR 0x20 -#define ACK_CHECK_EN 0x1 +#define ACK_CHECK_EN 0x1 /* ES8388 register */ #define ES8388_CONTROL1 0x00 @@ -78,28 +77,27 @@ #define ES8388_DACCONTROL29 0x33 #define ES8388_DACCONTROL30 0x34 -class ES8388AudioSink : public BufferedAudioSink -{ -public: - ES8388AudioSink(); - ~ES8388AudioSink(); - - bool begin(int sda = -1, int scl = -1, uint32_t frequency = 400000U); +class ES8388AudioSink : public BufferedAudioSink { + public: + ES8388AudioSink(); + ~ES8388AudioSink(); - enum ES8388_OUT - { - ES_MAIN, // this is the DAC output volume (both outputs) - ES_OUT1, // this is the additional gain for OUT1 - ES_OUT2 // this is the additional gain for OUT2 - }; + bool begin(int sda = -1, int scl = -1, uint32_t frequency = 400000U); - void mute(const ES8388_OUT out, const bool muted); - void volume(const ES8388_OUT out, const uint8_t vol); + enum ES8388_OUT { + ES_MAIN, // this is the DAC output volume (both outputs) + ES_OUT1, // this is the additional gain for OUT1 + ES_OUT2 // this is the additional gain for OUT2 + }; - void writeReg(uint8_t reg_add, uint8_t data); -private: - i2c_config_t i2c_config; - i2c_port_t i2c_port = 0; + void mute(const ES8388_OUT out, const bool muted); + void volume(const ES8388_OUT out, const uint8_t vol); + + void writeReg(uint8_t reg_add, uint8_t data); + + private: + i2c_config_t i2c_config; + i2c_port_t i2c_port = 0; }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES9018AudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES9018AudioSink.h index 986b53fa..a0ec5317 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES9018AudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ES9018AudioSink.h @@ -1,22 +1,22 @@ #ifndef ES9018AUDIOSINK_H #define ES9018AUDIOSINK_H -#include -#include -#include "BufferedAudioSink.h" #include #include -#include #include +#include +#include +#include +#include "BufferedAudioSink.h" #include "esp_err.h" #include "esp_log.h" -class ES9018AudioSink : public BufferedAudioSink -{ -public: - ES9018AudioSink(); - ~ES9018AudioSink(); -private: +class ES9018AudioSink : public BufferedAudioSink { + public: + ES9018AudioSink(); + ~ES9018AudioSink(); + + private: }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/InternalAudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/InternalAudioSink.h index 9c98523c..c4622bf4 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/InternalAudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/InternalAudioSink.h @@ -1,22 +1,22 @@ #ifndef INTERNALAUDIOSINK_H #define INTERNALAUDIOSINK_H -#include -#include -#include "BufferedAudioSink.h" #include #include -#include #include +#include +#include +#include +#include "BufferedAudioSink.h" #include "esp_err.h" #include "esp_log.h" -class InternalAudioSink : public BufferedAudioSink -{ -public: - InternalAudioSink(); - ~InternalAudioSink(); -private: +class InternalAudioSink : public BufferedAudioSink { + public: + InternalAudioSink(); + ~InternalAudioSink(); + + private: }; #endif diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/PCM5102AudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/PCM5102AudioSink.h index 77096a23..4f751064 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/PCM5102AudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/PCM5102AudioSink.h @@ -1,22 +1,22 @@ #ifndef PCM5102AUDIOSINK_H #define PCM5102AUDIOSINK_H -#include -#include -#include "BufferedAudioSink.h" #include #include -#include #include +#include +#include +#include +#include "BufferedAudioSink.h" #include "esp_err.h" #include "esp_log.h" -class PCM5102AudioSink : public BufferedAudioSink -{ -public: - PCM5102AudioSink(); - ~PCM5102AudioSink(); -private: +class PCM5102AudioSink : public BufferedAudioSink { + public: + PCM5102AudioSink(); + ~PCM5102AudioSink(); + + private: }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/SPDIFAudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/SPDIFAudioSink.h index 91ca110b..c92d983c 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/SPDIFAudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/SPDIFAudioSink.h @@ -1,26 +1,28 @@ #ifndef SPDIFAUDIOSINK_H #define SPDIFAUDIOSINK_H -#include -#include -#include "BufferedAudioSink.h" #include #include -#include #include +#include +#include +#include +#include "BufferedAudioSink.h" #include "esp_err.h" #include "esp_log.h" -class SPDIFAudioSink : public BufferedAudioSink -{ -private: - uint8_t spdifPin; -public: - explicit SPDIFAudioSink(uint8_t spdifPin); - ~SPDIFAudioSink() override; - void feedPCMFrames(const uint8_t *buffer, size_t bytes) override; - bool setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override; -private: +class SPDIFAudioSink : public BufferedAudioSink { + private: + uint8_t spdifPin; + + public: + explicit SPDIFAudioSink(uint8_t spdifPin); + ~SPDIFAudioSink() override; + void feedPCMFrames(const uint8_t* buffer, size_t bytes) override; + bool setParams(uint32_t sampleRate, uint8_t channelCount, + uint8_t bitDepth) override; + + private: }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/TAS5711AudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/TAS5711AudioSink.h index 23a705d8..b4319c3a 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/TAS5711AudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/TAS5711AudioSink.h @@ -1,30 +1,28 @@ #ifndef TAS5711AUDIOSINK_H #define TAS5711AUDIOSINK_H - -#include "driver/i2s.h" #include -#include -#include -#include "BufferedAudioSink.h" #include #include -#include #include +#include +#include +#include +#include "BufferedAudioSink.h" +#include "driver/i2s.h" #include "esp_err.h" #include "esp_log.h" -class TAS5711AudioSink : public BufferedAudioSink -{ -public: - TAS5711AudioSink(); - ~TAS5711AudioSink(); +class TAS5711AudioSink : public BufferedAudioSink { + public: + TAS5711AudioSink(); + ~TAS5711AudioSink(); + void writeReg(uint8_t reg, uint8_t value); - void writeReg(uint8_t reg, uint8_t value); -private: - i2c_config_t i2c_config; - i2c_port_t i2c_port = 0; + private: + i2c_config_t i2c_config; + i2c_port_t i2c_port = 0; }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ac101.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ac101.h index 39c17379..2ef3900b 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/ac101.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/ac101.h @@ -21,156 +21,156 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ - + #ifndef __AC101_H__ #define __AC101_H__ #include "esp_types.h" -#define AC101_ADDR 0x1a /*!< Device address*/ +#define AC101_ADDR 0x1a /*!< Device address*/ -#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */ -#define READ_BIT I2C_MASTER_READ /*!< I2C master read */ -#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ -#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ -#define ACK_VAL 0x0 /*!< I2C ack value */ -#define NACK_VAL 0x1 /*!< I2C nack value */ +#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */ +#define READ_BIT I2C_MASTER_READ /*!< I2C master read */ +#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ +#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ +#define ACK_VAL 0x0 /*!< I2C ack value */ +#define NACK_VAL 0x1 /*!< I2C nack value */ -#define CHIP_AUDIO_RS 0x00 -#define PLL_CTRL1 0x01 -#define PLL_CTRL2 0x02 -#define SYSCLK_CTRL 0x03 -#define MOD_CLK_ENA 0x04 -#define MOD_RST_CTRL 0x05 -#define I2S_SR_CTRL 0x06 -#define I2S1LCK_CTRL 0x10 -#define I2S1_SDOUT_CTRL 0x11 -#define I2S1_SDIN_CTRL 0x12 -#define I2S1_MXR_SRC 0x13 -#define I2S1_VOL_CTRL1 0x14 -#define I2S1_VOL_CTRL2 0x15 -#define I2S1_VOL_CTRL3 0x16 -#define I2S1_VOL_CTRL4 0x17 -#define I2S1_MXR_GAIN 0x18 -#define ADC_DIG_CTRL 0x40 -#define ADC_VOL_CTRL 0x41 -#define HMIC_CTRL1 0x44 -#define HMIC_CTRL2 0x45 -#define HMIC_STATUS 0x46 -#define DAC_DIG_CTRL 0x48 -#define DAC_VOL_CTRL 0x49 -#define DAC_MXR_SRC 0x4c -#define DAC_MXR_GAIN 0x4d -#define ADC_ANA_CTRL 0x50 -#define ADC_SRC 0x51 -#define ADC_SRCBST_CTRL 0x52 -#define OMIXER_DACA_CTRL 0x53 -#define OMIXER_SR 0x54 -#define OMIXER_BST1_CTRL 0x55 -#define HPOUT_CTRL 0x56 -#define SPKOUT_CTRL 0x58 -#define AC_DAC_DAPCTRL 0xa0 -#define AC_DAC_DAPHHPFC 0xa1 -#define AC_DAC_DAPLHPFC 0xa2 -#define AC_DAC_DAPLHAVC 0xa3 -#define AC_DAC_DAPLLAVC 0xa4 -#define AC_DAC_DAPRHAVC 0xa5 -#define AC_DAC_DAPRLAVC 0xa6 -#define AC_DAC_DAPHGDEC 0xa7 -#define AC_DAC_DAPLGDEC 0xa8 -#define AC_DAC_DAPHGATC 0xa9 -#define AC_DAC_DAPLGATC 0xaa -#define AC_DAC_DAPHETHD 0xab -#define AC_DAC_DAPLETHD 0xac -#define AC_DAC_DAPHGKPA 0xad -#define AC_DAC_DAPLGKPA 0xae -#define AC_DAC_DAPHGOPA 0xaf -#define AC_DAC_DAPLGOPA 0xb0 -#define AC_DAC_DAPOPT 0xb1 -#define DAC_DAP_ENA 0xb5 +#define CHIP_AUDIO_RS 0x00 +#define PLL_CTRL1 0x01 +#define PLL_CTRL2 0x02 +#define SYSCLK_CTRL 0x03 +#define MOD_CLK_ENA 0x04 +#define MOD_RST_CTRL 0x05 +#define I2S_SR_CTRL 0x06 +#define I2S1LCK_CTRL 0x10 +#define I2S1_SDOUT_CTRL 0x11 +#define I2S1_SDIN_CTRL 0x12 +#define I2S1_MXR_SRC 0x13 +#define I2S1_VOL_CTRL1 0x14 +#define I2S1_VOL_CTRL2 0x15 +#define I2S1_VOL_CTRL3 0x16 +#define I2S1_VOL_CTRL4 0x17 +#define I2S1_MXR_GAIN 0x18 +#define ADC_DIG_CTRL 0x40 +#define ADC_VOL_CTRL 0x41 +#define HMIC_CTRL1 0x44 +#define HMIC_CTRL2 0x45 +#define HMIC_STATUS 0x46 +#define DAC_DIG_CTRL 0x48 +#define DAC_VOL_CTRL 0x49 +#define DAC_MXR_SRC 0x4c +#define DAC_MXR_GAIN 0x4d +#define ADC_ANA_CTRL 0x50 +#define ADC_SRC 0x51 +#define ADC_SRCBST_CTRL 0x52 +#define OMIXER_DACA_CTRL 0x53 +#define OMIXER_SR 0x54 +#define OMIXER_BST1_CTRL 0x55 +#define HPOUT_CTRL 0x56 +#define SPKOUT_CTRL 0x58 +#define AC_DAC_DAPCTRL 0xa0 +#define AC_DAC_DAPHHPFC 0xa1 +#define AC_DAC_DAPLHPFC 0xa2 +#define AC_DAC_DAPLHAVC 0xa3 +#define AC_DAC_DAPLLAVC 0xa4 +#define AC_DAC_DAPRHAVC 0xa5 +#define AC_DAC_DAPRLAVC 0xa6 +#define AC_DAC_DAPHGDEC 0xa7 +#define AC_DAC_DAPLGDEC 0xa8 +#define AC_DAC_DAPHGATC 0xa9 +#define AC_DAC_DAPLGATC 0xaa +#define AC_DAC_DAPHETHD 0xab +#define AC_DAC_DAPLETHD 0xac +#define AC_DAC_DAPHGKPA 0xad +#define AC_DAC_DAPLGKPA 0xae +#define AC_DAC_DAPHGOPA 0xaf +#define AC_DAC_DAPLGOPA 0xb0 +#define AC_DAC_DAPOPT 0xb1 +#define DAC_DAP_ENA 0xb5 -typedef enum{ - SAMPLE_RATE_8000 = 0x0000, - SAMPLE_RATE_11052 = 0x1000, - SAMPLE_RATE_12000 = 0x2000, - SAMPLE_RATE_16000 = 0x3000, - SAMPLE_RATE_22050 = 0x4000, - SAMPLE_RATE_24000 = 0x5000, - SAMPLE_RATE_32000 = 0x6000, - SAMPLE_RATE_44100 = 0x7000, - SAMPLE_RATE_48000 = 0x8000, - SAMPLE_RATE_96000 = 0x9000, - SAMPLE_RATE_192000 = 0xa000, +typedef enum { + SAMPLE_RATE_8000 = 0x0000, + SAMPLE_RATE_11052 = 0x1000, + SAMPLE_RATE_12000 = 0x2000, + SAMPLE_RATE_16000 = 0x3000, + SAMPLE_RATE_22050 = 0x4000, + SAMPLE_RATE_24000 = 0x5000, + SAMPLE_RATE_32000 = 0x6000, + SAMPLE_RATE_44100 = 0x7000, + SAMPLE_RATE_48000 = 0x8000, + SAMPLE_RATE_96000 = 0x9000, + SAMPLE_RATE_192000 = 0xa000, } ac_adda_fs_i2s1_t; -typedef enum{ - BCLK_DIV_1 = 0x0, - BCLK_DIV_2 = 0x1, - BCLK_DIV_4 = 0x2, - BCLK_DIV_6 = 0x3, - BCLK_DIV_8 = 0x4, - BCLK_DIV_12 = 0x5, - BCLK_DIV_16 = 0x6, - BCLK_DIV_24 = 0x7, - BCLK_DIV_32 = 0x8, - BCLK_DIV_48 = 0x9, - BCLK_DIV_64 = 0xa, - BCLK_DIV_96 = 0xb, - BCLK_DIV_128 = 0xc, - BCLK_DIV_192 = 0xd, +typedef enum { + BCLK_DIV_1 = 0x0, + BCLK_DIV_2 = 0x1, + BCLK_DIV_4 = 0x2, + BCLK_DIV_6 = 0x3, + BCLK_DIV_8 = 0x4, + BCLK_DIV_12 = 0x5, + BCLK_DIV_16 = 0x6, + BCLK_DIV_24 = 0x7, + BCLK_DIV_32 = 0x8, + BCLK_DIV_48 = 0x9, + BCLK_DIV_64 = 0xa, + BCLK_DIV_96 = 0xb, + BCLK_DIV_128 = 0xc, + BCLK_DIV_192 = 0xd, } ac_i2s1_bclk_div_t; -typedef enum{ - LRCK_DIV_16 =0x0, - LRCK_DIV_32 =0x1, - LRCK_DIV_64 =0x2, - LRCK_DIV_128 =0x3, - LRCK_DIV_256 =0x4, +typedef enum { + LRCK_DIV_16 = 0x0, + LRCK_DIV_32 = 0x1, + LRCK_DIV_64 = 0x2, + LRCK_DIV_128 = 0x3, + LRCK_DIV_256 = 0x4, } ac_i2s1_lrck_div_t; typedef enum { - BIT_LENGTH_8_BITS = 0x00, - BIT_LENGTH_16_BITS = 0x01, - BIT_LENGTH_20_BITS = 0x02, - BIT_LENGTH_24_BITS = 0x03, + BIT_LENGTH_8_BITS = 0x00, + BIT_LENGTH_16_BITS = 0x01, + BIT_LENGTH_20_BITS = 0x02, + BIT_LENGTH_24_BITS = 0x03, } ac_bits_length_t; typedef enum { - AC_MODE_MIN = -1, - AC_MODE_SLAVE = 0x00, - AC_MODE_MASTER = 0x01, - AC_MODE_MAX, + AC_MODE_MIN = -1, + AC_MODE_SLAVE = 0x00, + AC_MODE_MASTER = 0x01, + AC_MODE_MAX, } ac_mode_sm_t; typedef enum { - AC_MODULE_MIN = -1, - AC_MODULE_ADC = 0x01, - AC_MODULE_DAC = 0x02, - AC_MODULE_ADC_DAC = 0x03, - AC_MODULE_LINE = 0x04, - AC_MODULE_MAX + AC_MODULE_MIN = -1, + AC_MODULE_ADC = 0x01, + AC_MODULE_DAC = 0x02, + AC_MODULE_ADC_DAC = 0x03, + AC_MODULE_LINE = 0x04, + AC_MODULE_MAX } ac_module_t; -typedef enum{ - SRC_MIC1 = 1, - SRC_MIC2 = 2, - SRC_LINEIN = 3, -}ac_output_mixer_source_t; +typedef enum { + SRC_MIC1 = 1, + SRC_MIC2 = 2, + SRC_LINEIN = 3, +} ac_output_mixer_source_t; typedef enum { - GAIN_N45DB = 0, - GAIN_N30DB = 1, - GAIN_N15DB = 2, - GAIN_0DB = 3, - GAIN_15DB = 4, - GAIN_30DB = 5, - GAIN_45DB = 6, - GAIN_60DB = 7, + GAIN_N45DB = 0, + GAIN_N30DB = 1, + GAIN_N15DB = 2, + GAIN_0DB = 3, + GAIN_15DB = 4, + GAIN_30DB = 5, + GAIN_45DB = 6, + GAIN_60DB = 7, } ac_output_mixer_gain_t; typedef struct { - ac_i2s1_bclk_div_t bclk_div; /*!< bits clock divide */ - ac_i2s1_lrck_div_t lclk_div; /*!< WS clock divide */ + ac_i2s1_bclk_div_t bclk_div; /*!< bits clock divide */ + ac_i2s1_lrck_div_t lclk_div; /*!< WS clock divide */ } ac_i2s_clock_t; #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/adac.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/adac.h index 1b1a2668..53d5a2bb 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/adac.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/adac.h @@ -9,18 +9,18 @@ * */ -#include "freertos/FreeRTOS.h" #include "driver/i2s.h" +#include "freertos/FreeRTOS.h" typedef enum { ADAC_ON = 0, ADAC_STANDBY, ADAC_OFF } adac_power_e; struct adac_s { - bool (*init)(int i2c_port_num, int i2s_num, i2s_config_t *config); - void (*deinit)(void); - void (*power)(adac_power_e mode); - void (*speaker)(bool active); - void (*headset)(bool active); - void (*volume)(unsigned left, unsigned right); + bool (*init)(int i2c_port_num, int i2s_num, i2s_config_t* config); + void (*deinit)(void); + void (*power)(adac_power_e mode); + void (*speaker)(bool active); + void (*headset)(bool active); + void (*volume)(unsigned left, unsigned right); }; extern struct adac_s dac_tas57xx; diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/es8311.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/es8311.h index e576dedd..17913d73 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/es8311.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/es8311.h @@ -18,80 +18,80 @@ /* * ES8311_REGISTER NAME_REG_REGISTER ADDRESS */ -#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/ +#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/ /* * Clock Scheme Register definition */ -#define ES8311_CLK_MANAGER_REG01 0x01 /* select clk src for mclk, enable clock for codec */ -#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */ -#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */ -#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */ -#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */ -#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */ -#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */ -#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */ -#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */ -#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */ -#define ES8311_SYSTEM_REG0B 0x0B /* system */ -#define ES8311_SYSTEM_REG0C 0x0C /* system */ -#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */ -#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */ -#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */ -#define ES8311_SYSTEM_REG10 0x10 /* system */ -#define ES8311_SYSTEM_REG11 0x11 /* system */ -#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */ -#define ES8311_SYSTEM_REG13 0x13 /* system */ -#define ES8311_SYSTEM_REG14 0x14 /* system, select DMIC, select analog pga gain */ -#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */ -#define ES8311_ADC_REG16 0x16 /* ADC */ -#define ES8311_ADC_REG17 0x17 /* ADC, volume */ -#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */ -#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */ -#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */ -#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */ -#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */ -#define ES8311_DAC_REG31 0x31 /* DAC, mute */ -#define ES8311_DAC_REG32 0x32 /* DAC, volume */ -#define ES8311_DAC_REG33 0x33 /* DAC, offset */ -#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */ -#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */ -#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */ -#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */ -#define ES8311_GP_REG45 0x45 /* GP CONTROL */ -#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ -#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */ -#define ES8311_CHVER_REGFF 0xFF /* VERSION */ -#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ - -#define ES8311_MAX_REGISTER 0xFF +#define ES8311_CLK_MANAGER_REG01 \ + 0x01 /* select clk src for mclk, enable clock for codec */ +#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */ +#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */ +#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */ +#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */ +#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */ +#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */ +#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */ +#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */ +#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */ +#define ES8311_SYSTEM_REG0B 0x0B /* system */ +#define ES8311_SYSTEM_REG0C 0x0C /* system */ +#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */ +#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */ +#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */ +#define ES8311_SYSTEM_REG10 0x10 /* system */ +#define ES8311_SYSTEM_REG11 0x11 /* system */ +#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */ +#define ES8311_SYSTEM_REG13 0x13 /* system */ +#define ES8311_SYSTEM_REG14 \ + 0x14 /* system, select DMIC, select analog pga gain */ +#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */ +#define ES8311_ADC_REG16 0x16 /* ADC */ +#define ES8311_ADC_REG17 0x17 /* ADC, volume */ +#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */ +#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */ +#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */ +#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */ +#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */ +#define ES8311_DAC_REG31 0x31 /* DAC, mute */ +#define ES8311_DAC_REG32 0x32 /* DAC, volume */ +#define ES8311_DAC_REG33 0x33 /* DAC, offset */ +#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */ +#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */ +#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */ +#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */ +#define ES8311_GP_REG45 0x45 /* GP CONTROL */ +#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ +#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */ +#define ES8311_CHVER_REGFF 0xFF /* VERSION */ +#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */ +#define ES8311_MAX_REGISTER 0xFF typedef struct { - ESCodecMode esMode; - i2c_port_t i2c_port_num; - i2c_config_t i2c_cfg; - DacOutput dacOutput; - AdcInput adcInput; + ESCodecMode esMode; + i2c_port_t i2c_port_num; + i2c_config_t i2c_cfg; + DacOutput dacOutput; + AdcInput adcInput; } Es8311Config; +#define AUDIO_CODEC_ES8311_DEFAULT() \ + { \ + .esMode = ES_MODE_SLAVE, \ + .i2c_port_num = I2C_NUM_0, \ + .i2c_cfg = {.mode = I2C_MODE_MASTER, \ + .sda_io_num = IIC_DATA, \ + .scl_io_num = IIC_CLK, \ + .sda_pullup_en = GPIO_PULLUP_ENABLE, \ + .scl_pullup_en = GPIO_PULLUP_ENABLE, \ + .master.clk_speed = 100000}, \ + .adcInput = ADC_INPUT_LINPUT1_RINPUT1, \ + .dacOutput = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | \ + DAC_OUTPUT_ROUT2, \ + }; -#define AUDIO_CODEC_ES8311_DEFAULT(){ \ - .esMode = ES_MODE_SLAVE, \ - .i2c_port_num = I2C_NUM_0, \ - .i2c_cfg = { \ - .mode = I2C_MODE_MASTER, \ - .sda_io_num = IIC_DATA, \ - .scl_io_num = IIC_CLK, \ - .sda_pullup_en = GPIO_PULLUP_ENABLE,\ - .scl_pullup_en = GPIO_PULLUP_ENABLE,\ - .master.clk_speed = 100000\ - }, \ - .adcInput = ADC_INPUT_LINPUT1_RINPUT1,\ - .dacOutput = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2,\ -}; - -int Es8311Init(Es8311Config *cfg); +int Es8311Init(Es8311Config* cfg); void Es8311Uninit(); esp_err_t Es8311GetRef(bool flag); esp_err_t Es7243Init(void); @@ -107,9 +107,9 @@ int Es8311Start(ESCodecModule mode); int Es8311Stop(ESCodecModule mode); int Es8311SetVoiceVolume(int volume); -int Es8311GetVoiceVolume(int *volume); +int Es8311GetVoiceVolume(int* volume); int Es8311SetVoiceMute(int enable); -int Es8311GetVoiceMute(int *mute); +int Es8311GetVoiceMute(int* mute); int Es8311SetMicGain(MicGain gain); int Es8311ConfigAdcInput(AdcInput input); diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/esp/esxxx_common.h b/components/spotify/cspot/bell/main/audio-sinks/include/esp/esxxx_common.h index bf8b35aa..3b4624ba 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/esp/esxxx_common.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/esp/esxxx_common.h @@ -2,165 +2,165 @@ #define __ESCODEC_COMMON_H__ typedef enum BitsLength { - BIT_LENGTH_MIN = -1, - BIT_LENGTH_16BITS = 0x03, - BIT_LENGTH_18BITS = 0x02, - BIT_LENGTH_20BITS = 0x01, - BIT_LENGTH_24BITS = 0x00, - BIT_LENGTH_32BITS = 0x04, - BIT_LENGTH_MAX, + BIT_LENGTH_MIN = -1, + BIT_LENGTH_16BITS = 0x03, + BIT_LENGTH_18BITS = 0x02, + BIT_LENGTH_20BITS = 0x01, + BIT_LENGTH_24BITS = 0x00, + BIT_LENGTH_32BITS = 0x04, + BIT_LENGTH_MAX, } BitsLength; typedef enum { - SAMPLE_RATE_MIN = -1, - SAMPLE_RATE_16K, - SAMPLE_RATE_32K, - SAMPLE_RATE_44_1K, - SAMPLE_RATE_MAX, + SAMPLE_RATE_MIN = -1, + SAMPLE_RATE_16K, + SAMPLE_RATE_32K, + SAMPLE_RATE_44_1K, + SAMPLE_RATE_MAX, } SampleRate; typedef enum { - MclkDiv_MIN = -1, - MclkDiv_1 = 1, - MclkDiv_2 = 2, - MclkDiv_3 = 3, - MclkDiv_4 = 4, - MclkDiv_6 = 5, - MclkDiv_8 = 6, - MclkDiv_9 = 7, - MclkDiv_11 = 8, - MclkDiv_12 = 9, - MclkDiv_16 = 10, - MclkDiv_18 = 11, - MclkDiv_22 = 12, - MclkDiv_24 = 13, - MclkDiv_33 = 14, - MclkDiv_36 = 15, - MclkDiv_44 = 16, - MclkDiv_48 = 17, - MclkDiv_66 = 18, - MclkDiv_72 = 19, - MclkDiv_5 = 20, - MclkDiv_10 = 21, - MclkDiv_15 = 22, - MclkDiv_17 = 23, - MclkDiv_20 = 24, - MclkDiv_25 = 25, - MclkDiv_30 = 26, - MclkDiv_32 = 27, - MclkDiv_34 = 28, - MclkDiv_7 = 29, - MclkDiv_13 = 30, - MclkDiv_14 = 31, - MclkDiv_MAX, + MclkDiv_MIN = -1, + MclkDiv_1 = 1, + MclkDiv_2 = 2, + MclkDiv_3 = 3, + MclkDiv_4 = 4, + MclkDiv_6 = 5, + MclkDiv_8 = 6, + MclkDiv_9 = 7, + MclkDiv_11 = 8, + MclkDiv_12 = 9, + MclkDiv_16 = 10, + MclkDiv_18 = 11, + MclkDiv_22 = 12, + MclkDiv_24 = 13, + MclkDiv_33 = 14, + MclkDiv_36 = 15, + MclkDiv_44 = 16, + MclkDiv_48 = 17, + MclkDiv_66 = 18, + MclkDiv_72 = 19, + MclkDiv_5 = 20, + MclkDiv_10 = 21, + MclkDiv_15 = 22, + MclkDiv_17 = 23, + MclkDiv_20 = 24, + MclkDiv_25 = 25, + MclkDiv_30 = 26, + MclkDiv_32 = 27, + MclkDiv_34 = 28, + MclkDiv_7 = 29, + MclkDiv_13 = 30, + MclkDiv_14 = 31, + MclkDiv_MAX, } SclkDiv; typedef enum { - LclkDiv_MIN = -1, - LclkDiv_128 = 0, - LclkDiv_192 = 1, - LclkDiv_256 = 2, - LclkDiv_384 = 3, - LclkDiv_512 = 4, - LclkDiv_576 = 5, - LclkDiv_768 = 6, - LclkDiv_1024 = 7, - LclkDiv_1152 = 8, - LclkDiv_1408 = 9, - LclkDiv_1536 = 10, - LclkDiv_2112 = 11, - LclkDiv_2304 = 12, + LclkDiv_MIN = -1, + LclkDiv_128 = 0, + LclkDiv_192 = 1, + LclkDiv_256 = 2, + LclkDiv_384 = 3, + LclkDiv_512 = 4, + LclkDiv_576 = 5, + LclkDiv_768 = 6, + LclkDiv_1024 = 7, + LclkDiv_1152 = 8, + LclkDiv_1408 = 9, + LclkDiv_1536 = 10, + LclkDiv_2112 = 11, + LclkDiv_2304 = 12, - LclkDiv_125 = 16, - LclkDiv_136 = 17, - LclkDiv_250 = 18, - LclkDiv_272 = 19, - LclkDiv_375 = 20, - LclkDiv_500 = 21, - LclkDiv_544 = 22, - LclkDiv_750 = 23, - LclkDiv_1000 = 24, - LclkDiv_1088 = 25, - LclkDiv_1496 = 26, - LclkDiv_1500 = 27, - LclkDiv_MAX, + LclkDiv_125 = 16, + LclkDiv_136 = 17, + LclkDiv_250 = 18, + LclkDiv_272 = 19, + LclkDiv_375 = 20, + LclkDiv_500 = 21, + LclkDiv_544 = 22, + LclkDiv_750 = 23, + LclkDiv_1000 = 24, + LclkDiv_1088 = 25, + LclkDiv_1496 = 26, + LclkDiv_1500 = 27, + LclkDiv_MAX, } LclkDiv; typedef enum { - ADC_INPUT_MIN = -1, - ADC_INPUT_LINPUT1_RINPUT1 = 0x00, - ADC_INPUT_MIC1 = 0x05, - ADC_INPUT_MIC2 = 0x06, - ADC_INPUT_LINPUT2_RINPUT2 = 0x50, - ADC_INPUT_DIFFERENCE = 0xf0, - ADC_INPUT_MAX, + ADC_INPUT_MIN = -1, + ADC_INPUT_LINPUT1_RINPUT1 = 0x00, + ADC_INPUT_MIC1 = 0x05, + ADC_INPUT_MIC2 = 0x06, + ADC_INPUT_LINPUT2_RINPUT2 = 0x50, + ADC_INPUT_DIFFERENCE = 0xf0, + ADC_INPUT_MAX, } AdcInput; typedef enum { - DAC_OUTPUT_MIN = -1, - DAC_OUTPUT_LOUT1 = 0x04, - DAC_OUTPUT_LOUT2 = 0x08, - DAC_OUTPUT_SPK = 0x09, - DAC_OUTPUT_ROUT1 = 0x10, - DAC_OUTPUT_ROUT2 = 0x20, - DAC_OUTPUT_ALL = 0x3c, - DAC_OUTPUT_MAX, + DAC_OUTPUT_MIN = -1, + DAC_OUTPUT_LOUT1 = 0x04, + DAC_OUTPUT_LOUT2 = 0x08, + DAC_OUTPUT_SPK = 0x09, + DAC_OUTPUT_ROUT1 = 0x10, + DAC_OUTPUT_ROUT2 = 0x20, + DAC_OUTPUT_ALL = 0x3c, + DAC_OUTPUT_MAX, } DacOutput; typedef enum { - D2SE_PGA_GAIN_MIN = -1, - D2SE_PGA_GAIN_DIS = 0, - D2SE_PGA_GAIN_EN = 1, - D2SE_PGA_GAIN_MAX = 2, + D2SE_PGA_GAIN_MIN = -1, + D2SE_PGA_GAIN_DIS = 0, + D2SE_PGA_GAIN_EN = 1, + D2SE_PGA_GAIN_MAX = 2, } D2SEPGA; typedef enum { - MIC_GAIN_MIN = -1, - MIC_GAIN_0DB = 0, - MIC_GAIN_3DB = 3, - MIC_GAIN_6DB = 6, - MIC_GAIN_9DB = 9, - MIC_GAIN_12DB = 12, - MIC_GAIN_15DB = 15, - MIC_GAIN_18DB = 18, - MIC_GAIN_21DB = 21, - MIC_GAIN_24DB = 24, + MIC_GAIN_MIN = -1, + MIC_GAIN_0DB = 0, + MIC_GAIN_3DB = 3, + MIC_GAIN_6DB = 6, + MIC_GAIN_9DB = 9, + MIC_GAIN_12DB = 12, + MIC_GAIN_15DB = 15, + MIC_GAIN_18DB = 18, + MIC_GAIN_21DB = 21, + MIC_GAIN_24DB = 24, #if defined CONFIG_CODEC_CHIP_IS_ES8311 - MIC_GAIN_30DB = 30, - MIC_GAIN_36DB = 36, - MIC_GAIN_42DB = 42, + MIC_GAIN_30DB = 30, + MIC_GAIN_36DB = 36, + MIC_GAIN_42DB = 42, #endif - MIC_GAIN_MAX, + MIC_GAIN_MAX, } MicGain; typedef enum { - ES_MODULE_MIN = -1, - ES_MODULE_ADC = 0x01, - ES_MODULE_DAC = 0x02, - ES_MODULE_ADC_DAC = 0x03, - ES_MODULE_LINE = 0x04, - ES_MODULE_MAX + ES_MODULE_MIN = -1, + ES_MODULE_ADC = 0x01, + ES_MODULE_DAC = 0x02, + ES_MODULE_ADC_DAC = 0x03, + ES_MODULE_LINE = 0x04, + ES_MODULE_MAX } ESCodecModule; typedef enum { - ES_MODE_MIN = -1, - ES_MODE_SLAVE = 0x00, - ES_MODE_MASTER = 0x01, - ES_MODE_MAX, + ES_MODE_MIN = -1, + ES_MODE_SLAVE = 0x00, + ES_MODE_MASTER = 0x01, + ES_MODE_MAX, } ESCodecMode; typedef enum { - ES_ = -1, - ES_I2S_NORMAL = 0, - ES_I2S_LEFT = 1, - ES_I2S_RIGHT = 2, - ES_I2S_DSP = 3, - ES_I2S_MAX + ES_ = -1, + ES_I2S_NORMAL = 0, + ES_I2S_LEFT = 1, + ES_I2S_RIGHT = 2, + ES_I2S_DSP = 3, + ES_I2S_MAX } ESCodecI2SFmt; typedef struct { - SclkDiv sclkDiv; - LclkDiv lclkDiv; + SclkDiv sclkDiv; + LclkDiv lclkDiv; } ESCodecI2sClock; -#endif //__ESCODEC_COMMON_H__ +#endif //__ESCODEC_COMMON_H__ diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/unix/ALSAAudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/unix/ALSAAudioSink.h index 1b1bd548..3a553e14 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/unix/ALSAAudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/unix/ALSAAudioSink.h @@ -1,124 +1,106 @@ #pragma once -#include -#include -#include "AudioSink.h" +#include #include #include -#include #include +#include #include #include +#include +#include "AudioSink.h" #define PCM_DEVICE "default" template -class RingbufferPointer -{ - typedef std::unique_ptr TPointer; +class RingbufferPointer { + typedef std::unique_ptr TPointer; -public: - explicit RingbufferPointer() - { - // create objects - for (int i = 0; i < SIZE; i++) - { - buf_[i] = std::make_unique(); - } + public: + explicit RingbufferPointer() { + // create objects + for (int i = 0; i < SIZE; i++) { + buf_[i] = std::make_unique(); + } + } + + bool push(TPointer& item) { + std::lock_guard lock(mutex_); + if (full()) + return false; + + std::swap(buf_[head_], item); + + if (full_) + tail_ = (tail_ + 1) % max_size_; + + head_ = (head_ + 1) % max_size_; + full_ = head_ == tail_; + + return true; + } + + bool pop(TPointer& item) { + std::lock_guard lock(mutex_); + if (empty()) + return false; + + std::swap(buf_[tail_], item); + + full_ = false; + tail_ = (tail_ + 1) % max_size_; + + return true; + } + + void reset() { + std::lock_guard lock(mutex_); + head_ = tail_; + full_ = false; + } + + bool empty() const { return (!full_ && (head_ == tail_)); } + + bool full() const { return full_; } + + int capacity() const { return max_size_; } + + int size() const { + int size = max_size_; + + if (!full_) { + if (head_ >= tail_) + size = head_ - tail_; + else + size = max_size_ + head_ - tail_; } - bool push(TPointer &item) - { - std::lock_guard lock(mutex_); - if (full()) - return false; + return size; + } - std::swap(buf_[head_], item); + private: + TPointer buf_[SIZE]; - if (full_) - tail_ = (tail_ + 1) % max_size_; - - head_ = (head_ + 1) % max_size_; - full_ = head_ == tail_; - - return true; - } - - bool pop(TPointer &item) - { - std::lock_guard lock(mutex_); - if (empty()) - return false; - - std::swap(buf_[tail_], item); - - full_ = false; - tail_ = (tail_ + 1) % max_size_; - - return true; - } - - void reset() - { - std::lock_guard lock(mutex_); - head_ = tail_; - full_ = false; - } - - bool empty() const - { - return (!full_ && (head_ == tail_)); - } - - bool full() const - { - return full_; - } - - int capacity() const - { - return max_size_; - } - - int size() const - { - int size = max_size_; - - if (!full_) - { - if (head_ >= tail_) - size = head_ - tail_; - else - size = max_size_ + head_ - tail_; - } - - return size; - } - -private: - TPointer buf_[SIZE]; - - std::mutex mutex_; - int head_ = 0; - int tail_ = 0; - const int max_size_ = SIZE; - bool full_ = 0; + std::mutex mutex_; + int head_ = 0; + int tail_ = 0; + const int max_size_ = SIZE; + bool full_ = 0; }; -class ALSAAudioSink : public AudioSink, public bell::Task -{ -public: - ALSAAudioSink(); - ~ALSAAudioSink(); - void feedPCMFrames(const uint8_t *buffer, size_t bytes); - void runTask(); +class ALSAAudioSink : public AudioSink, public bell::Task { + public: + ALSAAudioSink(); + ~ALSAAudioSink(); + void feedPCMFrames(const uint8_t* buffer, size_t bytes); + void runTask(); -private: - RingbufferPointer, 3> ringbuffer; - unsigned int pcm; - snd_pcm_t *pcm_handle; - snd_pcm_hw_params_t *params; - snd_pcm_uframes_t frames; - int buff_size; - std::vector buff; + private: + RingbufferPointer, 3> ringbuffer; + unsigned int pcm; + snd_pcm_t* pcm_handle; + snd_pcm_hw_params_t* params; + snd_pcm_uframes_t frames; + int buff_size; + std::vector buff; }; diff --git a/components/spotify/cspot/bell/main/audio-sinks/include/unix/NamedPipeAudioSink.h b/components/spotify/cspot/bell/main/audio-sinks/include/unix/NamedPipeAudioSink.h index cbce8884..f987df91 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/include/unix/NamedPipeAudioSink.h +++ b/components/spotify/cspot/bell/main/audio-sinks/include/unix/NamedPipeAudioSink.h @@ -1,16 +1,17 @@ #pragma once -#include -#include -#include "AudioSink.h" +#include // for size_t +#include // for uint8_t +#include // for ofstream -class NamedPipeAudioSink : public AudioSink -{ -public: - NamedPipeAudioSink(); - ~NamedPipeAudioSink(); - void feedPCMFrames(const uint8_t *buffer, size_t bytes); - -private: - std::ofstream namedPipeFile; +#include "AudioSink.h" // for AudioSink + +class NamedPipeAudioSink : public AudioSink { + public: + NamedPipeAudioSink(); + ~NamedPipeAudioSink(); + void feedPCMFrames(const uint8_t* buffer, size_t bytes); + + private: + std::ofstream namedPipeFile; }; diff --git a/components/spotify/cspot/bell/main/audio-sinks/unix/ALSAAudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/unix/ALSAAudioSink.cpp index 0219fbbe..7b63d848 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/unix/ALSAAudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/unix/ALSAAudioSink.cpp @@ -1,101 +1,92 @@ #include "ALSAAudioSink.h" -ALSAAudioSink::ALSAAudioSink() : Task("", 0, 0, 0) -{ - /* Open the PCM device in playback mode */ - if (pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, - SND_PCM_STREAM_PLAYBACK, 0) < 0) - { - printf("ERROR: Can't open \"%s\" PCM device. %s\n", - PCM_DEVICE, snd_strerror(pcm)); +ALSAAudioSink::ALSAAudioSink() : Task("", 0, 0, 0) { + /* Open the PCM device in playback mode */ + if (pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < + 0) { + printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, + snd_strerror(pcm)); + } + + /* Allocate parameters object and fill it with default values*/ + snd_pcm_hw_params_alloca(¶ms); + + snd_pcm_hw_params_any(pcm_handle, params); + + /* Set parameters */ + if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params, + SND_PCM_ACCESS_RW_INTERLEAVED) < 0) + printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm)); + + if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params, + SND_PCM_FORMAT_S16_LE) < 0) + printf("ERROR: Can't set format. %s\n", snd_strerror(pcm)); + + if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, 2) < 0) + printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm)); + unsigned int rate = 44100; + if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0) + printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm)); + unsigned int periodTime = 800; + int dir = -1; + snd_pcm_hw_params_set_period_time_near(pcm_handle, params, &periodTime, &dir); + /* Write parameters */ + if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0) + printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm)); + + /* Resume information */ + printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle)); + + printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle))); + unsigned int tmp; + snd_pcm_hw_params_get_channels(params, &tmp); + printf("channels: %i ", tmp); + if (tmp == 1) + printf("(mono)\n"); + else if (tmp == 2) + printf("(stereo)\n"); + + snd_pcm_hw_params_get_period_time(params, &tmp, NULL); + printf("period_time = %d\n", tmp); + snd_pcm_hw_params_get_period_size(params, &frames, 0); + + this->buff_size = frames * 2 * 2 /* 2 -> sample size */; + printf("required buff_size: %d\n", buff_size); + this->startTask(); +} + +ALSAAudioSink::~ALSAAudioSink() { + snd_pcm_drain(pcm_handle); + snd_pcm_close(pcm_handle); +} + +void ALSAAudioSink::runTask() { + std::unique_ptr> dataPtr; + while (true) { + if (!this->ringbuffer.pop(dataPtr)) { + usleep(100); + continue; } + if (pcm = snd_pcm_writei(pcm_handle, dataPtr->data(), this->frames) == + -EPIPE) { - /* Allocate parameters object and fill it with default values*/ - snd_pcm_hw_params_alloca(¶ms); - - snd_pcm_hw_params_any(pcm_handle, params); - - /* Set parameters */ - if (pcm = snd_pcm_hw_params_set_access(pcm_handle, params, - SND_PCM_ACCESS_RW_INTERLEAVED) < 0) - printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm)); - - if (pcm = snd_pcm_hw_params_set_format(pcm_handle, params, - SND_PCM_FORMAT_S16_LE) < 0) - printf("ERROR: Can't set format. %s\n", snd_strerror(pcm)); - - if (pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, 2) < 0) - printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm)); - unsigned int rate = 44100; - if (pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0) - printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm)); - unsigned int periodTime = 800; - int dir = -1; - snd_pcm_hw_params_set_period_time_near(pcm_handle, params, &periodTime, &dir); - /* Write parameters */ - if (pcm = snd_pcm_hw_params(pcm_handle, params) < 0) - printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm)); - - /* Resume information */ - printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle)); - - printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle))); - unsigned int tmp; - snd_pcm_hw_params_get_channels(params, &tmp); - printf("channels: %i ", tmp); - if (tmp == 1) - printf("(mono)\n"); - else if (tmp == 2) - printf("(stereo)\n"); - - snd_pcm_hw_params_get_period_time(params, &tmp, NULL); - printf("period_time = %d\n", tmp); - snd_pcm_hw_params_get_period_size(params, &frames, 0); - - this->buff_size = frames * 2 * 2 /* 2 -> sample size */; - printf("required buff_size: %d\n", buff_size); - this->startTask(); -} - -ALSAAudioSink::~ALSAAudioSink() -{ - snd_pcm_drain(pcm_handle); - snd_pcm_close(pcm_handle); -} - -void ALSAAudioSink::runTask() -{ - std::unique_ptr> dataPtr; - while (true) - { - if (!this->ringbuffer.pop(dataPtr)) - { - usleep(100); - continue; - } - if (pcm = snd_pcm_writei(pcm_handle, dataPtr->data(), this->frames) == -EPIPE) - { - - snd_pcm_prepare(pcm_handle); - } - else if (pcm < 0) - { - printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm)); - } + snd_pcm_prepare(pcm_handle); + } else if (pcm < 0) { + printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(pcm)); } + } } -void ALSAAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes) -{ +void ALSAAudioSink::feedPCMFrames(const uint8_t* buffer, size_t bytes) { - buff.insert(buff.end(), buffer, buffer + bytes); - while (buff.size() > this->buff_size) - { - auto ptr = std::make_unique>(this->buff.begin(), this->buff.begin() + this->buff_size); - this->buff = std::vector(this->buff.begin() + this->buff_size, this->buff.end()); - while (!this->ringbuffer.push(ptr)) - { - usleep(100); - }; - } + buff.insert(buff.end(), buffer, buffer + bytes); + while (buff.size() > this->buff_size) { + auto ptr = std::make_unique>( + this->buff.begin(), this->buff.begin() + this->buff_size); + this->buff = std::vector(this->buff.begin() + this->buff_size, + this->buff.end()); + while (!this->ringbuffer.push(ptr)) { + usleep(100); + }; + } } diff --git a/components/spotify/cspot/bell/main/audio-sinks/unix/NamedPipeAudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/unix/NamedPipeAudioSink.cpp index 2c310786..90bb1422 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/unix/NamedPipeAudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/unix/NamedPipeAudioSink.cpp @@ -1,21 +1,19 @@ #include "NamedPipeAudioSink.h" -NamedPipeAudioSink::NamedPipeAudioSink() -{ - printf("Start\n"); - this->namedPipeFile = std::ofstream("outputFifo", std::ios::binary); - printf("stop\n"); +#include // for printf +NamedPipeAudioSink::NamedPipeAudioSink() { + printf("Start\n"); + this->namedPipeFile = std::ofstream("outputFifo", std::ios::binary); + printf("stop\n"); } -NamedPipeAudioSink::~NamedPipeAudioSink() -{ - this->namedPipeFile.close(); +NamedPipeAudioSink::~NamedPipeAudioSink() { + this->namedPipeFile.close(); } -void NamedPipeAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes) -{ - // Write the actual data - this->namedPipeFile.write((char*)buffer, (long)bytes); - this->namedPipeFile.flush(); +void NamedPipeAudioSink::feedPCMFrames(const uint8_t* buffer, size_t bytes) { + // Write the actual data + this->namedPipeFile.write((char*)buffer, (long)bytes); + this->namedPipeFile.flush(); } diff --git a/components/spotify/cspot/bell/main/audio-sinks/unix/PortAudioSink.cpp b/components/spotify/cspot/bell/main/audio-sinks/unix/PortAudioSink.cpp index 51ff7ed3..4fec893f 100644 --- a/components/spotify/cspot/bell/main/audio-sinks/unix/PortAudioSink.cpp +++ b/components/spotify/cspot/bell/main/audio-sinks/unix/PortAudioSink.cpp @@ -1,65 +1,57 @@ #include "PortAudioSink.h" -PortAudioSink::PortAudioSink() -{ - Pa_Initialize(); - this->setParams(44100, 2, 16); +PortAudioSink::PortAudioSink() { + Pa_Initialize(); + this->setParams(44100, 2, 16); } -bool PortAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) { - if (stream) { - Pa_StopStream(stream); - } - PaStreamParameters outputParameters; - outputParameters.device = Pa_GetDefaultOutputDevice(); - if (outputParameters.device == paNoDevice) { - printf("PortAudio: Default audio device not found!\n"); - // exit(0); - } - printf("PortAudio: Default audio device not found!\n"); - - outputParameters.channelCount = channelCount; - switch (bitDepth) { - case 32: - outputParameters.sampleFormat = paInt32; - break; - case 24: - outputParameters.sampleFormat = paInt24; - break; - case 16: - outputParameters.sampleFormat = paInt16; - break; - case 8: - outputParameters.sampleFormat = paInt8; - break; - default: - outputParameters.sampleFormat = paInt16; - break; - } - outputParameters.suggestedLatency = 0.050; - outputParameters.hostApiSpecificStreamInfo = NULL; - - PaError err = Pa_OpenStream( - &stream, - NULL, - &outputParameters, - sampleRate, - 4096 / (channelCount * bitDepth / 8), - paClipOff, - NULL, // blocking api - NULL - ); - Pa_StartStream(stream); - return !err; -} - -PortAudioSink::~PortAudioSink() -{ +bool PortAudioSink::setParams(uint32_t sampleRate, uint8_t channelCount, + uint8_t bitDepth) { + if (stream) { Pa_StopStream(stream); - Pa_Terminate(); + } + PaStreamParameters outputParameters; + outputParameters.device = Pa_GetDefaultOutputDevice(); + if (outputParameters.device == paNoDevice) { + printf("PortAudio: Default audio device not found!\n"); + // exit(0); + } + printf("PortAudio: Default audio device not found!\n"); + + outputParameters.channelCount = channelCount; + switch (bitDepth) { + case 32: + outputParameters.sampleFormat = paInt32; + break; + case 24: + outputParameters.sampleFormat = paInt24; + break; + case 16: + outputParameters.sampleFormat = paInt16; + break; + case 8: + outputParameters.sampleFormat = paInt8; + break; + default: + outputParameters.sampleFormat = paInt16; + break; + } + outputParameters.suggestedLatency = 0.050; + outputParameters.hostApiSpecificStreamInfo = NULL; + + PaError err = Pa_OpenStream(&stream, NULL, &outputParameters, sampleRate, + 4096 / (channelCount * bitDepth / 8), paClipOff, + NULL, // blocking api + NULL); + Pa_StartStream(stream); + return !err; } -void PortAudioSink::feedPCMFrames(const uint8_t *buffer, size_t bytes) -{ - Pa_WriteStream(stream, buffer, bytes / 4); +PortAudioSink::~PortAudioSink() { + Pa_StopStream(stream); + Pa_Terminate(); +} + +void PortAudioSink::feedPCMFrames(const uint8_t* buffer, size_t bytes) { + Pa_WriteStream(stream, buffer, bytes / 4); } diff --git a/components/spotify/cspot/bell/main/io/BellHTTPServer.cpp b/components/spotify/cspot/bell/main/io/BellHTTPServer.cpp index d6c7d4eb..2b24c82d 100644 --- a/components/spotify/cspot/bell/main/io/BellHTTPServer.cpp +++ b/components/spotify/cspot/bell/main/io/BellHTTPServer.cpp @@ -1,8 +1,14 @@ #include "BellHTTPServer.h" -#include -#include -#include "CivetServer.h" -#include "civetweb.h" + +#include // for memcpy +#include // for assert +#include // for exception +#include // for scoped_lock +#include // for sregex_token_iterator, regex + +#include "BellLogger.h" // for AbstractLogger, BELL_LOG, bell +#include "CivetServer.h" // for CivetServer, CivetWebSocketHandler +#include "civetweb.h" // for mg_get_request_info, mg_printf, mg_set_user... using namespace bell; @@ -195,7 +201,8 @@ std::unique_ptr BellHTTPServer::makeJsonResponse( return response; } -std::unique_ptr BellHTTPServer::makeEmptyResponse() { +std::unique_ptr +BellHTTPServer::makeEmptyResponse() { auto response = std::make_unique(); return response; } @@ -225,8 +232,10 @@ void BellHTTPServer::registerNotFound(HTTPHandler handler) { std::unordered_map BellHTTPServer::extractParams( struct mg_connection* conn) { + void* data = mg_get_user_connection_data(conn); + assert(data != nullptr); std::unordered_map& params = - *(std::unordered_map*) - mg_get_user_connection_data(conn); + *(std::unordered_map*)data; + return params; } diff --git a/components/spotify/cspot/bell/main/io/BellTar.cpp b/components/spotify/cspot/bell/main/io/BellTar.cpp index edebfc50..4ab0237a 100644 --- a/components/spotify/cspot/bell/main/io/BellTar.cpp +++ b/components/spotify/cspot/bell/main/io/BellTar.cpp @@ -1,14 +1,18 @@ #include "BellTar.h" -#include -#include + +#include // for mkdir using namespace bell::BellTar; -#include -#include // for sprintf, snprintf and sscanf -#include // for rand -#include // for strlen and memset -#include // for time +#include // for min +#include // for assert +#include // for uint8_t +#include // for sprintf, size_t, sscanf, EOF, NULL +#include // for rand +#include // for memset, strlen +#include // for time +#include // for ofstream +#include // for vector #ifdef _WIN32 #include #endif @@ -59,7 +63,7 @@ void header_set_metadata(tar_header* header) { std::memset(header, 0, sizeof(tar_header)); std::sprintf(header->magic, "ustar"); - std::sprintf(header->mtime, "%011lo", (unsigned long) std::time(NULL)); + std::sprintf(header->mtime, "%011lo", (unsigned long)std::time(NULL)); std::sprintf(header->mode, "%07o", 0644); std::sprintf(header->uname, "unkown"); // ... a bit random std::sprintf(header->gname, "users"); diff --git a/components/spotify/cspot/bell/main/io/BinaryReader.cpp b/components/spotify/cspot/bell/main/io/BinaryReader.cpp index f7ef1f29..13aab639 100644 --- a/components/spotify/cspot/bell/main/io/BinaryReader.cpp +++ b/components/spotify/cspot/bell/main/io/BinaryReader.cpp @@ -1,72 +1,69 @@ #include "BinaryReader.h" -#include + +#include // for size_t +#include // for uint8_t +#include // for remove_extent_t + +#include "ByteStream.h" // for ByteStream bell::BinaryReader::BinaryReader(std::shared_ptr stream) { - this->stream = stream; + this->stream = stream; } size_t bell::BinaryReader::position() { - return stream->position(); + return stream->position(); } size_t bell::BinaryReader::size() { - return stream->size(); + return stream->size(); } void bell::BinaryReader::close() { - stream->close(); + stream->close(); } void bell::BinaryReader::skip(size_t pos) { - std::vector b(pos); - stream->read(&b[0], pos); + std::vector b(pos); + stream->read(&b[0], pos); } int32_t bell::BinaryReader::readInt() { - uint8_t b[4]; - if (stream->read((uint8_t *) b,4) != 4) - return 0; - - return static_cast( - (b[3]) | - (b[2] << 8) | - (b[1] << 16)| - (b[0] << 24) ); + uint8_t b[4]; + if (stream->read((uint8_t*)b, 4) != 4) + return 0; + + return static_cast((b[3]) | (b[2] << 8) | (b[1] << 16) | + (b[0] << 24)); } int16_t bell::BinaryReader::readShort() { - uint8_t b[2]; - if (stream->read((uint8_t *) b,2) != 2) - return 0; - - return static_cast( - (b[1]) | - (b[0] << 8)); + uint8_t b[2]; + if (stream->read((uint8_t*)b, 2) != 2) + return 0; + + return static_cast((b[1]) | (b[0] << 8)); } - uint32_t bell::BinaryReader::readUInt() { - return readInt() & 0xffffffffL; + return readInt() & 0xffffffffL; } uint8_t bell::BinaryReader::readByte() { - uint8_t b[1]; - if (stream->read((uint8_t *) b,1) != 1) - return 0; - return b[0]; + uint8_t b[1]; + if (stream->read((uint8_t*)b, 1) != 1) + return 0; + return b[0]; } std::vector bell::BinaryReader::readBytes(size_t size) { - std::vector data(size); - stream->read(&data[0], size); - return data; + std::vector data(size); + stream->read(&data[0], size); + return data; } long long bell::BinaryReader::readLong() { - long high = readInt(); - long low = readInt(); + long high = readInt(); + long low = readInt(); - return static_cast( - ((long long) high << 32) | low ); + return static_cast(((long long)high << 32) | low); } - diff --git a/components/spotify/cspot/bell/main/io/BinaryStream.cpp b/components/spotify/cspot/bell/main/io/BinaryStream.cpp index a5a445ee..38a7a9ff 100644 --- a/components/spotify/cspot/bell/main/io/BinaryStream.cpp +++ b/components/spotify/cspot/bell/main/io/BinaryStream.cpp @@ -1,5 +1,5 @@ #include -#include +#include // for runtime_error using namespace bell; diff --git a/components/spotify/cspot/bell/main/io/BufferedStream.cpp b/components/spotify/cspot/bell/main/io/BufferedStream.cpp index a41f2439..4af2c3dd 100644 --- a/components/spotify/cspot/bell/main/io/BufferedStream.cpp +++ b/components/spotify/cspot/bell/main/io/BufferedStream.cpp @@ -1,172 +1,182 @@ #include "BufferedStream.h" -#include -BufferedStream::BufferedStream( - const std::string &taskName, - uint32_t bufferSize, - uint32_t readThreshold, - uint32_t readSize, - uint32_t readyThreshold, - uint32_t notReadyThreshold, - bool waitForReady) - : bell::Task(taskName, 4096, 5, 0) { - this->bufferSize = bufferSize; - this->readAt = bufferSize - readThreshold; - this->readSize = readSize; - this->readyThreshold = readyThreshold; - this->notReadyThreshold = notReadyThreshold; - this->waitForReady = waitForReady; - this->buf = static_cast(malloc(bufferSize)); - this->bufEnd = buf + bufferSize; - reset(); +#include // for free, malloc +#include // for min +#include // for uint32_t +#include // for memcpy +#include // for remove_extent_t + +BufferedStream::BufferedStream(const std::string& taskName, uint32_t bufferSize, + uint32_t readThreshold, uint32_t readSize, + uint32_t readyThreshold, + uint32_t notReadyThreshold, bool waitForReady) + : bell::Task(taskName, 4096, 5, 0) { + this->bufferSize = bufferSize; + this->readAt = bufferSize - readThreshold; + this->readSize = readSize; + this->readyThreshold = readyThreshold; + this->notReadyThreshold = notReadyThreshold; + this->waitForReady = waitForReady; + this->buf = static_cast(malloc(bufferSize)); + this->bufEnd = buf + bufferSize; + reset(); } BufferedStream::~BufferedStream() { - this->close(); - free(buf); + this->close(); + free(buf); } void BufferedStream::close() { - this->terminate = true; - this->readSem.give(); // force a read operation - const std::lock_guard lock(runningMutex); - if (this->source) - this->source->close(); - this->source = nullptr; + this->terminate = true; + this->readSem.give(); // force a read operation + const std::lock_guard lock(runningMutex); + if (this->source) + this->source->close(); + this->source = nullptr; } void BufferedStream::reset() { - this->bufReadPtr = this->buf; - this->bufWritePtr = this->buf; - this->readTotal = 0; - this->bufferTotal = 0; - this->readAvailable = 0; - this->terminate = false; + this->bufReadPtr = this->buf; + this->bufWritePtr = this->buf; + this->readTotal = 0; + this->bufferTotal = 0; + this->readAvailable = 0; + this->terminate = false; } -bool BufferedStream::open(const std::shared_ptr &stream) { - if (this->running) - this->close(); - reset(); - this->source = stream; - startTask(); - return source.get(); +bool BufferedStream::open(const std::shared_ptr& stream) { + if (this->running) + this->close(); + reset(); + this->source = stream; + startTask(); + return source.get(); } -bool BufferedStream::open(const StreamReader &newReader, uint32_t initialOffset) { - if (this->running) - this->close(); - reset(); - this->reader = newReader; - this->bufferTotal = initialOffset; - startTask(); - return source.get(); +bool BufferedStream::open(const StreamReader& newReader, + uint32_t initialOffset) { + if (this->running) + this->close(); + reset(); + this->reader = newReader; + this->bufferTotal = initialOffset; + startTask(); + return source.get(); } bool BufferedStream::isReady() const { - return readAvailable >= readyThreshold; + return readAvailable >= readyThreshold; } bool BufferedStream::isNotReady() const { - return readAvailable < notReadyThreshold; + return readAvailable < notReadyThreshold; } size_t BufferedStream::skip(size_t len) { - return read(nullptr, len); + return read(nullptr, len); } size_t BufferedStream::position() { - return readTotal; + return readTotal; } size_t BufferedStream::size() { - return source->size(); + return source->size(); } -uint32_t BufferedStream::lengthBetween(uint8_t *me, uint8_t *other) { - const std::lock_guard lock(readMutex); - if (other <= me) { - // buf .... other ...... me ........ bufEnd - // buf .... me/other ........ bufEnd - return bufEnd - me; - } else { - // buf ........ me ........ other .... bufEnd - return other - me; - } +uint32_t BufferedStream::lengthBetween(uint8_t* me, uint8_t* other) { + const std::lock_guard lock(readMutex); + if (other <= me) { + // buf .... other ...... me ........ bufEnd + // buf .... me/other ........ bufEnd + return bufEnd - me; + } else { + // buf ........ me ........ other .... bufEnd + return other - me; + } } -size_t BufferedStream::read(uint8_t *dst, size_t len) { - if (waitForReady && isNotReady()) { - while ((source || reader) && !isReady()) {} // end waiting after termination - } - if (!running && !readAvailable) { - reset(); - return 0; - } - uint32_t read = 0; - uint32_t toReadTotal = std::min(readAvailable.load(), static_cast(len)); - while (toReadTotal > 0) { - uint32_t toRead = std::min(toReadTotal, lengthBetween(bufReadPtr, bufWritePtr)); - if (dst) { - memcpy(dst, bufReadPtr, toRead); - dst += toRead; - } - readAvailable -= toRead; - bufReadPtr += toRead; - if (bufReadPtr >= bufEnd) - bufReadPtr = buf; - toReadTotal -= toRead; - read += toRead; - readTotal += toRead; - } - this->readSem.give(); - return read; +size_t BufferedStream::read(uint8_t* dst, size_t len) { + if (waitForReady && isNotReady()) { + while ((source || reader) && !isReady()) { + } // end waiting after termination + } + if (!running && !readAvailable) { + reset(); + return 0; + } + uint32_t read = 0; + uint32_t toReadTotal = + std::min(readAvailable.load(), static_cast(len)); + while (toReadTotal > 0) { + uint32_t toRead = + std::min(toReadTotal, lengthBetween(bufReadPtr, bufWritePtr)); + if (dst) { + memcpy(dst, bufReadPtr, toRead); + dst += toRead; + } + readAvailable -= toRead; + bufReadPtr += toRead; + if (bufReadPtr >= bufEnd) + bufReadPtr = buf; + toReadTotal -= toRead; + read += toRead; + readTotal += toRead; + } + this->readSem.give(); + return read; } void BufferedStream::runTask() { - const std::lock_guard lock(runningMutex); - running = true; - if (!source && reader) { - // get the initial request on the task's thread - source = reader(this->bufferTotal); - } - while (!terminate) { - if (!source) - break; - if (isReady()) { - // buffer ready, wait for any read operations - this->readSem.wait(); - } - if (terminate) - break; - if (readAvailable > readAt) - continue; - // here, the buffer needs re-filling - uint32_t len; - bool wasReady = isReady(); - do { - uint32_t toRead = std::min(readSize, lengthBetween(bufWritePtr, bufReadPtr)); - if (!source) { - len = 0; - break; - } - len = source->read(bufWritePtr, toRead); - readAvailable += len; - bufferTotal += len; - bufWritePtr += len; - if (bufWritePtr >= bufEnd) // TODO is == enough here? - bufWritePtr = buf; - } while (len && readSize < bufferSize - readAvailable); // loop until there's no more free space in the buffer - if (!len && reader) - source = reader(bufferTotal); - else if (!len) - terminate = true; - // signal that buffer is ready for reading - if (!wasReady && isReady()) { - this->readySem.give(); - } - } - source = nullptr; - reader = nullptr; - running = false; + const std::lock_guard lock(runningMutex); + running = true; + if (!source && reader) { + // get the initial request on the task's thread + source = reader(this->bufferTotal); + } + while (!terminate) { + if (!source) + break; + if (isReady()) { + // buffer ready, wait for any read operations + this->readSem.wait(); + } + if (terminate) + break; + if (readAvailable > readAt) + continue; + // here, the buffer needs re-filling + uint32_t len; + bool wasReady = isReady(); + do { + uint32_t toRead = + std::min(readSize, lengthBetween(bufWritePtr, bufReadPtr)); + if (!source) { + len = 0; + break; + } + len = source->read(bufWritePtr, toRead); + readAvailable += len; + bufferTotal += len; + bufWritePtr += len; + if (bufWritePtr >= bufEnd) // TODO is == enough here? + bufWritePtr = buf; + } while ( + len && + readSize < + bufferSize - + readAvailable); // loop until there's no more free space in the buffer + if (!len && reader) + source = reader(bufferTotal); + else if (!len) + terminate = true; + // signal that buffer is ready for reading + if (!wasReady && isReady()) { + this->readySem.give(); + } + } + source = nullptr; + reader = nullptr; + running = false; } diff --git a/components/spotify/cspot/bell/main/io/CircularBuffer.cpp b/components/spotify/cspot/bell/main/io/CircularBuffer.cpp index 700bf0e4..2e5eff2b 100644 --- a/components/spotify/cspot/bell/main/io/CircularBuffer.cpp +++ b/components/spotify/cspot/bell/main/io/CircularBuffer.cpp @@ -1,89 +1,85 @@ #include "CircularBuffer.h" +#include // for min + using namespace bell; -CircularBuffer::CircularBuffer(size_t dataCapacity) -{ - this->dataCapacity = dataCapacity; - buffer = std::vector(dataCapacity); - this->dataSemaphore = std::make_unique(5); +CircularBuffer::CircularBuffer(size_t dataCapacity) { + this->dataCapacity = dataCapacity; + buffer = std::vector(dataCapacity); + this->dataSemaphore = std::make_unique(5); }; -size_t CircularBuffer::write(const uint8_t *data, size_t bytes) -{ - if (bytes == 0) - return 0; +size_t CircularBuffer::write(const uint8_t* data, size_t bytes) { + if (bytes == 0) + return 0; - std::lock_guard guard(bufferMutex); - size_t bytesToWrite = std::min(bytes, dataCapacity - dataSize); - // Write in a single step - if (bytesToWrite <= dataCapacity - endIndex) - { - memcpy(buffer.data() + endIndex, data, bytesToWrite); - endIndex += bytesToWrite; - if (endIndex == dataCapacity) - endIndex = 0; - } + std::lock_guard guard(bufferMutex); + size_t bytesToWrite = std::min(bytes, dataCapacity - dataSize); + // Write in a single step + if (bytesToWrite <= dataCapacity - endIndex) { + memcpy(buffer.data() + endIndex, data, bytesToWrite); + endIndex += bytesToWrite; + if (endIndex == dataCapacity) + endIndex = 0; + } - // Write in two steps - else { - size_t firstChunkSize = dataCapacity - endIndex; - memcpy(buffer.data() + endIndex, data, firstChunkSize); - size_t secondChunkSize = bytesToWrite - firstChunkSize; - memcpy(buffer.data(), data + firstChunkSize, secondChunkSize); - endIndex = secondChunkSize; - } + // Write in two steps + else { + size_t firstChunkSize = dataCapacity - endIndex; + memcpy(buffer.data() + endIndex, data, firstChunkSize); + size_t secondChunkSize = bytesToWrite - firstChunkSize; + memcpy(buffer.data(), data + firstChunkSize, secondChunkSize); + endIndex = secondChunkSize; + } - dataSize += bytesToWrite; + dataSize += bytesToWrite; - // this->dataSemaphore->give(); - return bytesToWrite; + // this->dataSemaphore->give(); + return bytesToWrite; } void CircularBuffer::emptyBuffer() { - std::lock_guard guard(bufferMutex); - begIndex = 0; - dataSize = 0; - endIndex = 0; + std::lock_guard guard(bufferMutex); + begIndex = 0; + dataSize = 0; + endIndex = 0; } void CircularBuffer::emptyExcept(size_t sizeToSet) { - std::lock_guard guard(bufferMutex); - if (sizeToSet > dataSize) - sizeToSet = dataSize; - dataSize = sizeToSet; - endIndex = begIndex + sizeToSet; - if (endIndex > dataCapacity) { - endIndex -= dataCapacity; - } + std::lock_guard guard(bufferMutex); + if (sizeToSet > dataSize) + sizeToSet = dataSize; + dataSize = sizeToSet; + endIndex = begIndex + sizeToSet; + if (endIndex > dataCapacity) { + endIndex -= dataCapacity; + } } -size_t CircularBuffer::read(uint8_t *data, size_t bytes) -{ - if (bytes == 0) - return 0; +size_t CircularBuffer::read(uint8_t* data, size_t bytes) { + if (bytes == 0) + return 0; - std::lock_guard guard(bufferMutex); - size_t bytesToRead = std::min(bytes, dataSize); + std::lock_guard guard(bufferMutex); + size_t bytesToRead = std::min(bytes, dataSize); - // Read in a single step - if (bytesToRead <= dataCapacity - begIndex) - { - memcpy(data, buffer.data() + begIndex, bytesToRead); - begIndex += bytesToRead; - if (begIndex == dataCapacity) - begIndex = 0; - } - // Read in two steps - else - { - size_t firstChunkSize = dataCapacity - begIndex; - memcpy(data, buffer.data() + begIndex, firstChunkSize); - size_t secondChunkSize = bytesToRead - firstChunkSize; - memcpy(data + firstChunkSize, buffer.data(), secondChunkSize); - begIndex = secondChunkSize; - } + // Read in a single step + if (bytesToRead <= dataCapacity - begIndex) { + memcpy(data, buffer.data() + begIndex, bytesToRead); + begIndex += bytesToRead; + if (begIndex == dataCapacity) + begIndex = 0; + } + // Read in two steps + else { + size_t firstChunkSize = dataCapacity - begIndex; + memcpy(data, buffer.data() + begIndex, firstChunkSize); + size_t secondChunkSize = bytesToRead - firstChunkSize; + memcpy(data + firstChunkSize, buffer.data(), secondChunkSize); + begIndex = secondChunkSize; + } - dataSize -= bytesToRead; - return bytesToRead; + dataSize -= bytesToRead; + return bytesToRead; } diff --git a/components/spotify/cspot/bell/main/io/EncodedAudioStream.cpp b/components/spotify/cspot/bell/main/io/EncodedAudioStream.cpp index d8e2e99d..6d80eb8e 100644 --- a/components/spotify/cspot/bell/main/io/EncodedAudioStream.cpp +++ b/components/spotify/cspot/bell/main/io/EncodedAudioStream.cpp @@ -1,6 +1,14 @@ #include "EncodedAudioStream.h" -#include +#include // for memcpy, memmove +#include // for runtime_error +#include // for remove_extent_t +#include // for move + +#include "BellLogger.h" // for AbstractLogger, BELL_LOG, bell +#include "ByteStream.h" // for ByteStream +#include "DecoderGlobals.h" // for DecodersInstance, decodersInstance, AAC_... + using namespace bell; EncodedAudioStream::EncodedAudioStream() { @@ -171,5 +179,4 @@ void EncodedAudioStream::guessDataFormat() { } } -void EncodedAudioStream::readFully(uint8_t* dst, size_t nbytes) { -} +void EncodedAudioStream::readFully(uint8_t* dst, size_t nbytes) {} diff --git a/components/spotify/cspot/bell/main/io/FileStream.cpp b/components/spotify/cspot/bell/main/io/FileStream.cpp index 02db8956..e1d3aaa2 100644 --- a/components/spotify/cspot/bell/main/io/FileStream.cpp +++ b/components/spotify/cspot/bell/main/io/FileStream.cpp @@ -1,70 +1,61 @@ #include "FileStream.h" +#include // for runtime_error + +#include "BellLogger.h" // for bell + using namespace bell; -FileStream::FileStream(const std::string& path, std::string read) -{ - file = fopen(path.c_str(), "rb"); - if (file == NULL) - { - throw std::runtime_error("Could not open file: " + path); - } +FileStream::FileStream(const std::string& path, std::string read) { + file = fopen(path.c_str(), "rb"); + if (file == NULL) { + throw std::runtime_error("Could not open file: " + path); + } } -FileStream::~FileStream() -{ - close(); +FileStream::~FileStream() { + close(); } -size_t FileStream::read(uint8_t *buf, size_t nbytes) -{ - if (file == NULL) - { - throw std::runtime_error("Stream is closed"); - } +size_t FileStream::read(uint8_t* buf, size_t nbytes) { + if (file == NULL) { + throw std::runtime_error("Stream is closed"); + } - return fread(buf, 1, nbytes, file); + return fread(buf, 1, nbytes, file); } -size_t FileStream::skip(size_t nbytes) -{ - if (file == NULL) - { - throw std::runtime_error("Stream is closed"); - } +size_t FileStream::skip(size_t nbytes) { + if (file == NULL) { + throw std::runtime_error("Stream is closed"); + } - return fseek(file, nbytes, SEEK_CUR); + return fseek(file, nbytes, SEEK_CUR); } -size_t FileStream::position() -{ - if (file == NULL) - { - throw std::runtime_error("Stream is closed"); - } +size_t FileStream::position() { + if (file == NULL) { + throw std::runtime_error("Stream is closed"); + } - return ftell(file); + return ftell(file); } -size_t FileStream::size() -{ - if (file == NULL) - { - throw std::runtime_error("Stream is closed"); - } +size_t FileStream::size() { + if (file == NULL) { + throw std::runtime_error("Stream is closed"); + } - size_t pos = ftell(file); - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - fseek(file, pos, SEEK_SET); - return size; + size_t pos = ftell(file); + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, pos, SEEK_SET); + return size; } -void FileStream::close() -{ - if (file != NULL) - { - fclose(file); - file = NULL; - } +void FileStream::close() { + if (file != NULL) { + fclose(file); + file = NULL; + } } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/io/HTTPClient.cpp b/components/spotify/cspot/bell/main/io/HTTPClient.cpp index b78b46cd..f91ad907 100644 --- a/components/spotify/cspot/bell/main/io/HTTPClient.cpp +++ b/components/spotify/cspot/bell/main/io/HTTPClient.cpp @@ -1,5 +1,14 @@ #include "HTTPClient.h" +#include // for memcpy +#include // for transform +#include // for assert +#include // for tolower +#include // for operator<<, basic_ostream +#include // for runtime_error + +#include "BellSocket.h" // for bell + using namespace bell; void HTTPClient::Response::connect(const std::string& url) { diff --git a/components/spotify/cspot/bell/main/io/SocketStream.cpp b/components/spotify/cspot/bell/main/io/SocketStream.cpp index 2a3bc5a6..2b2b2cab 100644 --- a/components/spotify/cspot/bell/main/io/SocketStream.cpp +++ b/components/spotify/cspot/bell/main/io/SocketStream.cpp @@ -1,9 +1,17 @@ #include "SocketStream.h" +#include // for uint8_t +#include // for NULL, ssize_t + +#include "TCPSocket.h" // for TCPSocket +#include "TLSSocket.h" // for TLSSocket + using namespace bell; int SocketBuffer::open(const std::string& hostname, int port, bool isSSL) { - if (internalSocket != nullptr) { close(); } + if (internalSocket != nullptr) { + close(); + } if (isSSL) { internalSocket = std::make_unique(); } else { diff --git a/components/spotify/cspot/bell/main/io/TLSSocket.cpp b/components/spotify/cspot/bell/main/io/TLSSocket.cpp index 96b5e823..489748d3 100644 --- a/components/spotify/cspot/bell/main/io/TLSSocket.cpp +++ b/components/spotify/cspot/bell/main/io/TLSSocket.cpp @@ -1,5 +1,14 @@ #include "TLSSocket.h" -#include "X509Bundle.h" + +#include // for mbedtls_ctr_drbg_free, mbedtls_ctr_... +#include // for mbedtls_entropy_free, mbedtls_entro... +#include // for mbedtls_net_connect, mbedtls_net_free +#include // for mbedtls_ssl_conf_authmode, mbedtls_... +#include // for strlen, NULL +#include // for runtime_error + +#include "BellLogger.h" // for AbstractLogger, BELL_LOG +#include "X509Bundle.h" // for shouldVerify, attach /** * Platform TLSSocket implementation for the mbedtls diff --git a/components/spotify/cspot/bell/main/io/URLParser.cpp b/components/spotify/cspot/bell/main/io/URLParser.cpp index 55fd21c5..4a50ab1e 100644 --- a/components/spotify/cspot/bell/main/io/URLParser.cpp +++ b/components/spotify/cspot/bell/main/io/URLParser.cpp @@ -4,40 +4,50 @@ namespace bell { #ifdef BELL_DISABLE_REGEX void URLParser::parse(const char* url, std::vector& match) { - match[0] = url; - char scratch[512]; + match[0] = url; + char scratch[512]; - /* Parsing the following (http|https://[host][/path][?query]#hash] as in regex + /* Parsing the following (http|https://[host][/path][?query]#hash] as in regex * below. This needs to be changed if you update that regex */ - - // get the schema - if (sscanf(url, "%[^:]:/", scratch) > 0) match[1] = scratch; - - // get the host - if (sscanf(url, "htt%*[^:]://%512[^/#?]", scratch) > 0) match[2] = scratch; - // get the path - url = strstr(url, match[2].c_str()) + match[2].size(); - if (sscanf(url, "/%512[^?]", scratch) > 0) match[3] = scratch; - else if (*url && *url != '?' && *url != '#') url++; - - // get the query - if (match[3].size()) url += match[3].size() + 1; - if (sscanf(url, "?%512[^#]", scratch) > 0) match[4] = scratch; + // get the schema + if (sscanf(url, "%[^:]:/", scratch) > 0) + match[1] = scratch; - // get the hash - if (match[4].size()) url += match[4].size() + 1; - if (sscanf(url, "#%512s", scratch) > 0) match[5] = scratch; + // get the host + if (sscanf(url, "htt%*[^:]://%512[^/#?]", scratch) > 0) + match[2] = scratch; - // fix the acquired items - match[3] = "/" + match[3]; - if (match[4].size()) match[4] = "?" + match[4]; + // get the path + url = strstr(url, match[2].c_str()) + match[2].size(); + if (sscanf(url, "/%512[^?]", scratch) > 0) + match[3] = scratch; + else if (*url && *url != '?' && *url != '#') + url++; - // need at least schema and host - if (match[1].size() == 0 || match[2].size() == 0) match.clear(); -} -#else + // get the query + if (match[3].size()) + url += match[3].size() + 1; + if (sscanf(url, "?%512[^#]", scratch) > 0) + match[4] = scratch; + + // get the hash + if (match[4].size()) + url += match[4].size() + 1; + if (sscanf(url, "#%512s", scratch) > 0) + match[5] = scratch; + + // fix the acquired items + match[3] = "/" + match[3]; + if (match[4].size()) + match[4] = "?" + match[4]; + + // need at least schema and host + if (match[1].size() == 0 || match[2].size() == 0) + match.clear(); +} +#else const std::regex URLParser::urlParseRegex = std::regex( - "^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(\\?(?:[^#]*))?(#(?:.*))?"); + "^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(\\?(?:[^#]*))?(#(?:.*))?"); #endif -} +} // namespace bell diff --git a/components/spotify/cspot/bell/main/io/X509Bundle.cpp b/components/spotify/cspot/bell/main/io/X509Bundle.cpp index 8b7b757b..ffcdd134 100644 --- a/components/spotify/cspot/bell/main/io/X509Bundle.cpp +++ b/components/spotify/cspot/bell/main/io/X509Bundle.cpp @@ -1,5 +1,15 @@ #include "X509Bundle.h" +#include // for mbedtls_md, mbedtls_md_get_size +#include // for mbedtls_pk_can_do, mbedtls_pk_pa... +#include // for mbedtls_ssl_conf_ca_chain, mbedt... +#include // for mbedtls_x509_buf, MBEDTLS_ERR_X5... +#include // for free, calloc +#include // for memcmp, memcpy +#include // for runtime_error + +#include "BellLogger.h" // for AbstractLogger, BELL_LOG + using namespace bell::X509Bundle; static mbedtls_x509_crt s_dummy_crt; @@ -21,7 +31,8 @@ int bell::X509Bundle::crtCheckCertificate(mbedtls_x509_crt* child, if ((ret = mbedtls_pk_parse_public_key(&parent.pk, pub_key_buf, pub_key_len)) != 0) { - BELL_LOG(error, TAG, "PK parse failed with error %X", ret); + BELL_LOG(error, TAG, "PK parse failed with error 0x%04x, key len = %d", ret, + pub_key_len); goto cleanup; } @@ -110,6 +121,8 @@ int bell::X509Bundle::crtVerifyCallback(void* buf, mbedtls_x509_crt* crt, ret = crtCheckCertificate( child, s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET + name_len, key_len); + } else { + BELL_LOG(error, TAG, "Certificate not found in bundle"); } if (ret == 0) { @@ -138,10 +151,13 @@ void bell::X509Bundle::init(const uint8_t* x509_bundle, size_t bundle_size) { throw std::runtime_error("Unable to allocate memory for bundle"); } + bundleBytes.resize(bundle_size); + memcpy(bundleBytes.data(), x509_bundle, bundle_size); + const uint8_t* cur_crt; /* This is the maximum region that is allowed to access */ - const uint8_t* bundle_end = x509_bundle + bundle_size; - cur_crt = x509_bundle + BUNDLE_HEADER_OFFSET; + const uint8_t* bundle_end = bundleBytes.data() + bundle_size; + cur_crt = bundleBytes.data() + BUNDLE_HEADER_OFFSET; for (int i = 0; i < num_certs; i++) { crts[i] = cur_crt; diff --git a/components/spotify/cspot/bell/main/io/include/BellHTTPServer.h b/components/spotify/cspot/bell/main/io/include/BellHTTPServer.h index fc58dd96..c65a3587 100644 --- a/components/spotify/cspot/bell/main/io/include/BellHTTPServer.h +++ b/components/spotify/cspot/bell/main/io/include/BellHTTPServer.h @@ -1,22 +1,18 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "CivetServer.h" -#include "civetweb.h" +#include // for bell +#include // for uint8_t +#include // for free, size_t +#include // for function +#include // for map +#include // for unique_ptr +#include // for mutex +#include // for string, hash, operator==, operator< +#include // for unordered_map +#include // for pair +#include // for vector + +#include "CivetServer.h" // for CivetServer, CivetHandler using namespace bell; namespace bell { @@ -46,7 +42,9 @@ class BellHTTPServer : public CivetHandler { } } }; - typedef std::function(struct mg_connection* conn)> HTTPHandler; + typedef std::function( + struct mg_connection* conn)> + HTTPHandler; typedef std::function WSStateHandler; typedef std::function @@ -79,7 +77,8 @@ class BellHTTPServer : public CivetHandler { std::vector getListeningPorts() { return server->getListeningPorts(); }; void close() { server->close(); } - std::unique_ptr makeJsonResponse(const std::string& json, int status = 200); + std::unique_ptr makeJsonResponse(const std::string& json, + int status = 200); std::unique_ptr makeEmptyResponse(); void registerNotFound(HTTPHandler handler); @@ -88,7 +87,8 @@ class BellHTTPServer : public CivetHandler { void registerWS(const std::string&, WSDataHandler dataHandler, WSStateHandler stateHandler); - static std::unordered_map extractParams(struct mg_connection* conn); + static std::unordered_map extractParams( + struct mg_connection* conn); private: std::unique_ptr server; diff --git a/components/spotify/cspot/bell/main/io/include/BellSocket.h b/components/spotify/cspot/bell/main/io/include/BellSocket.h index 5c887377..5eff94eb 100644 --- a/components/spotify/cspot/bell/main/io/include/BellSocket.h +++ b/components/spotify/cspot/bell/main/io/include/BellSocket.h @@ -14,6 +14,6 @@ class Socket { virtual size_t read(uint8_t* buf, size_t len) = 0; virtual bool isOpen() = 0; virtual void close() = 0; + virtual int getFd() = 0; }; } // namespace bell - diff --git a/components/spotify/cspot/bell/main/io/include/BellTar.h b/components/spotify/cspot/bell/main/io/include/BellTar.h index 1f4af0d4..ef1b7e6a 100644 --- a/components/spotify/cspot/bell/main/io/include/BellTar.h +++ b/components/spotify/cspot/bell/main/io/include/BellTar.h @@ -1,8 +1,7 @@ #pragma once -#include -#include -#include +#include // for istream, ostream +#include // for string namespace bell::BellTar { typedef long long unsigned file_size_t; diff --git a/components/spotify/cspot/bell/main/io/include/BinaryReader.h b/components/spotify/cspot/bell/main/io/include/BinaryReader.h index dd0a4f9a..25befc9a 100644 --- a/components/spotify/cspot/bell/main/io/include/BinaryReader.h +++ b/components/spotify/cspot/bell/main/io/include/BinaryReader.h @@ -1,31 +1,28 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include "ByteStream.h" +#include // for uint8_t, int16_t, int32_t, uint32_t +#include // for size_t +#include // for shared_ptr +#include // for vector -namespace bell -{ - class BinaryReader - { - std::shared_ptr stream; - size_t currentPos = 0; +namespace bell { +class ByteStream; - public: - BinaryReader(std::shared_ptr stream); - int32_t readInt(); - int16_t readShort(); - uint32_t readUInt(); - long long readLong(); - void close(); - uint8_t readByte(); - size_t size(); - size_t position(); - std::vector readBytes(size_t); - void skip(size_t); - }; -} \ No newline at end of file +class BinaryReader { + std::shared_ptr stream; + size_t currentPos = 0; + + public: + BinaryReader(std::shared_ptr stream); + int32_t readInt(); + int16_t readShort(); + uint32_t readUInt(); + long long readLong(); + void close(); + uint8_t readByte(); + size_t size(); + size_t position(); + std::vector readBytes(size_t); + void skip(size_t); +}; +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/io/include/BinaryStream.h b/components/spotify/cspot/bell/main/io/include/BinaryStream.h index 1da7677a..78cdd66a 100644 --- a/components/spotify/cspot/bell/main/io/include/BinaryStream.h +++ b/components/spotify/cspot/bell/main/io/include/BinaryStream.h @@ -1,10 +1,11 @@ #pragma once #ifndef ESP_PLATFORM -#include +#include // for endian #endif -#include -#include +#include // for int16_t, int32_t, int64_t, uint16_t, uint32_t +#include // for byte +#include // for istream, ostream namespace bell { class BinaryStream { diff --git a/components/spotify/cspot/bell/main/io/include/BufferedStream.h b/components/spotify/cspot/bell/main/io/include/BufferedStream.h index 94041062..2acce8f8 100644 --- a/components/spotify/cspot/bell/main/io/include/BufferedStream.h +++ b/components/spotify/cspot/bell/main/io/include/BufferedStream.h @@ -1,12 +1,16 @@ #pragma once -#include "ByteStream.h" -#include "BellTask.h" -#include "WrappedSemaphore.h" -#include -#include -#include -#include +#include // for size_t +#include // for uint32_t, uint8_t +#include // for atomic +#include // for function +#include // for shared_ptr +#include // for mutex +#include // for string + +#include "BellTask.h" // for Task +#include "ByteStream.h" // for ByteStream +#include "WrappedSemaphore.h" // for WrappedSemaphore /** * This class implements a wrapper around an arbitrary bell::ByteStream, @@ -26,12 +30,12 @@ * method correctly, such as that 0 is returned if, and only if the stream ends. */ class BufferedStream : public bell::ByteStream, bell::Task { - public: - typedef std::shared_ptr StreamPtr; - typedef std::function StreamReader; + public: + typedef std::shared_ptr StreamPtr; + typedef std::function StreamReader; - public: - /** + public: + /** * @param taskName name to use for the reading task * @param bufferSize total size of the reading buffer * @param readThreshold how much can be read before refilling the buffer @@ -41,22 +45,18 @@ class BufferedStream : public bell::ByteStream, bell::Task { * @param waitForReady whether to wait for the buffer to be ready during reading * @param endWithSource whether to end the streaming as soon as source returns 0 from read() */ - BufferedStream( - const std::string &taskName, - uint32_t bufferSize, - uint32_t readThreshold, - uint32_t readSize, - uint32_t readyThreshold, - uint32_t notReadyThreshold, - bool waitForReady = false); - ~BufferedStream() override; - bool open(const StreamPtr &stream); - bool open(const StreamReader &newReader, uint32_t initialOffset = 0); - void close() override; + BufferedStream(const std::string& taskName, uint32_t bufferSize, + uint32_t readThreshold, uint32_t readSize, + uint32_t readyThreshold, uint32_t notReadyThreshold, + bool waitForReady = false); + ~BufferedStream() override; + bool open(const StreamPtr& stream); + bool open(const StreamReader& newReader, uint32_t initialOffset = 0); + void close() override; - // inherited methods - public: - /** + // inherited methods + public: + /** * Read len bytes from the buffer to dst. If waitForReady is enabled * and readAvailable is lower than notReadyThreshold, the function * will block until readyThreshold bytes is available. @@ -65,61 +65,63 @@ class BufferedStream : public bell::ByteStream, bell::Task { * if the buffer does not contain len bytes available), or 0 if the source * stream is already closed and there is no reader attached. */ - size_t read(uint8_t *dst, size_t len) override; - size_t skip(size_t len) override; - size_t position() override; - size_t size() override; + size_t read(uint8_t* dst, size_t len) override; + size_t skip(size_t len) override; + size_t position() override; + size_t size() override; - // stream status - public: - /** + // stream status + public: + /** * Total amount of bytes served to read(). */ - uint32_t readTotal; - /** + uint32_t readTotal; + /** * Total amount of bytes read from source. */ - uint32_t bufferTotal; - /** + uint32_t bufferTotal; + /** * Amount of bytes available to read from the buffer. */ - std::atomic readAvailable; - /** + std::atomic readAvailable; + /** * Whether the caller should start reading the data. This indicates that a safe * amount (determined by readyThreshold) of data is available in the buffer. */ - bool isReady() const; - /** + bool isReady() const; + /** * Whether the caller should stop reading the data. This indicates that the amount of data * available for reading is decreasing to a non-safe value, as data is being read * faster than it can be buffered. */ - bool isNotReady() const; - /** + bool isNotReady() const; + /** * Semaphore that is given when the buffer becomes ready (isReady() == true). Caller can * wait for the semaphore instead of continuously querying isReady(). */ - bell::WrappedSemaphore readySem; + bell::WrappedSemaphore readySem; - private: - std::mutex runningMutex; - bool running = false; - bool terminate = false; - bell::WrappedSemaphore readSem; // signal to start writing to buffer after reading from it - std::mutex readMutex; // mutex for locking read operations during writing, and vice versa - uint32_t bufferSize; - uint32_t readAt; - uint32_t readSize; - uint32_t readyThreshold; - uint32_t notReadyThreshold; - bool waitForReady; - uint8_t *buf; - uint8_t *bufEnd; - uint8_t *bufReadPtr; - uint8_t *bufWritePtr; - StreamPtr source; - StreamReader reader; - void runTask() override; - void reset(); - uint32_t lengthBetween(uint8_t *me, uint8_t *other); + private: + std::mutex runningMutex; + bool running = false; + bool terminate = false; + bell::WrappedSemaphore + readSem; // signal to start writing to buffer after reading from it + std::mutex + readMutex; // mutex for locking read operations during writing, and vice versa + uint32_t bufferSize; + uint32_t readAt; + uint32_t readSize; + uint32_t readyThreshold; + uint32_t notReadyThreshold; + bool waitForReady; + uint8_t* buf; + uint8_t* bufEnd; + uint8_t* bufReadPtr; + uint8_t* bufWritePtr; + StreamPtr source; + StreamReader reader; + void runTask() override; + void reset(); + uint32_t lengthBetween(uint8_t* me, uint8_t* other); }; diff --git a/components/spotify/cspot/bell/main/io/include/ByteStream.h b/components/spotify/cspot/bell/main/io/include/ByteStream.h index 21b09420..aad1ebf1 100644 --- a/components/spotify/cspot/bell/main/io/include/ByteStream.h +++ b/components/spotify/cspot/bell/main/io/include/ByteStream.h @@ -1,27 +1,25 @@ #ifndef BELL_BYTE_READER_H #define BELL_BYTE_READER_H -#include #include +#include /** * A class for reading bytes from a stream. Further implemented in HTTPStream.h */ -namespace bell -{ - class ByteStream - { - public: - ByteStream(){}; - virtual ~ByteStream() = default; +namespace bell { +class ByteStream { + public: + ByteStream(){}; + virtual ~ByteStream() = default; - virtual size_t read(uint8_t *buf, size_t nbytes) = 0; - virtual size_t skip(size_t nbytes) = 0; + virtual size_t read(uint8_t* buf, size_t nbytes) = 0; + virtual size_t skip(size_t nbytes) = 0; - virtual size_t position() = 0; - virtual size_t size() = 0; - virtual void close() = 0; - }; -} + virtual size_t position() = 0; + virtual size_t size() = 0; + virtual void close() = 0; +}; +} // namespace bell #endif diff --git a/components/spotify/cspot/bell/main/io/include/CircularBuffer.h b/components/spotify/cspot/bell/main/io/include/CircularBuffer.h index df4e4a17..08a66b05 100644 --- a/components/spotify/cspot/bell/main/io/include/CircularBuffer.h +++ b/components/spotify/cspot/bell/main/io/include/CircularBuffer.h @@ -1,39 +1,35 @@ #pragma once -#include -#include -#include -#include -#include -#include "WrappedSemaphore.h" +#include // for uint8_t +#include // for size_t +#include // for unique_ptr +#include // for mutex +#include // for vector +#include "WrappedSemaphore.h" // for WrappedSemaphore namespace bell { class CircularBuffer { - public: - CircularBuffer(size_t dataCapacity); + public: + CircularBuffer(size_t dataCapacity); - std::unique_ptr dataSemaphore; + std::unique_ptr dataSemaphore; - size_t size() const { - return dataSize; - } + size_t size() const { return dataSize; } - size_t capacity() const { - return dataCapacity; - } + size_t capacity() const { return dataCapacity; } - size_t write(const uint8_t *data, size_t bytes); - size_t read(uint8_t *data, size_t bytes); - void emptyBuffer(); - void emptyExcept(size_t size); + size_t write(const uint8_t* data, size_t bytes); + size_t read(uint8_t* data, size_t bytes); + void emptyBuffer(); + void emptyExcept(size_t size); - private: - std::mutex bufferMutex; - size_t begIndex = 0; - size_t endIndex = 0; - size_t dataSize = 0; - size_t dataCapacity = 0; - std::vector buffer; + private: + std::mutex bufferMutex; + size_t begIndex = 0; + size_t endIndex = 0; + size_t dataSize = 0; + size_t dataCapacity = 0; + std::vector buffer; }; -} // namespace bell \ No newline at end of file +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/io/include/EncodedAudioStream.h b/components/spotify/cspot/bell/main/io/include/EncodedAudioStream.h index 2938f9d4..ce8a682e 100644 --- a/components/spotify/cspot/bell/main/io/include/EncodedAudioStream.h +++ b/components/spotify/cspot/bell/main/io/include/EncodedAudioStream.h @@ -1,15 +1,17 @@ #pragma once -#include -#include +#include // for size_t +#include // for uint8_t +#include // for shared_ptr, unique_ptr +#include // for basic_string, string +#include // for vector -#include "BellLogger.h" -#include "ByteStream.h" -#include "DecoderGlobals.h" -#include "aacdec.h" -#include "mp3dec.h" +#include "aacdec.h" // for AACFrameInfo +#include "mp3dec.h" // for MP3FrameInfo namespace bell { +class ByteStream; + class EncodedAudioStream { public: EncodedAudioStream(); diff --git a/components/spotify/cspot/bell/main/io/include/FileStream.h b/components/spotify/cspot/bell/main/io/include/FileStream.h index 4456affd..ae3ae514 100644 --- a/components/spotify/cspot/bell/main/io/include/FileStream.h +++ b/components/spotify/cspot/bell/main/io/include/FileStream.h @@ -1,10 +1,9 @@ #pragma once -#include -#include -#include -#include -#include +#include // for ByteStream +#include // for uint8_t +#include // for size_t, FILE +#include // for string /* * FileStream @@ -12,17 +11,15 @@ * A class for reading and writing to files implementing the ByteStream interface. * */ -namespace bell -{ - class FileStream : public ByteStream - { - public: - FileStream(const std::string& path, std::string mode); - ~FileStream(); +namespace bell { +class FileStream : public ByteStream { + public: + FileStream(const std::string& path, std::string mode); + ~FileStream(); - FILE* file; + FILE* file; - /* + /* * Reads data from the stream. * * @param buf The buffer to read data into. @@ -30,18 +27,18 @@ namespace bell * @return The number of bytes read. * @throws std::runtime_error if the stream is closed. */ - size_t read(uint8_t *buf, size_t nbytes); + size_t read(uint8_t* buf, size_t nbytes); - /* + /* * Skips nbytes bytes in the stream. */ - size_t skip(size_t nbytes); + size_t skip(size_t nbytes); - size_t position(); + size_t position(); - size_t size(); + size_t size(); - // Closes the connection - void close(); - }; -} + // Closes the connection + void close(); +}; +} // namespace bell diff --git a/components/spotify/cspot/bell/main/io/include/HTTPClient.h b/components/spotify/cspot/bell/main/io/include/HTTPClient.h index 7ce164d9..052ce6c6 100644 --- a/components/spotify/cspot/bell/main/io/include/HTTPClient.h +++ b/components/spotify/cspot/bell/main/io/include/HTTPClient.h @@ -1,24 +1,20 @@ #pragma once -#include +#include // for size_t +#include // for uint8_t, int32_t +#include // for make_unique, unique_ptr +#include // for string +#include // for string_view +#include // for pair +#include // for vector -#include -#include -#include -#include -#include -#include -#include - -#include "BellSocket.h" -#include "ByteStream.h" -#include "SocketStream.h" -#include "URLParser.h" +#include "SocketStream.h" // for SocketStream +#include "URLParser.h" // for URLParser #ifndef BELL_DISABLE_FMT -#include "fmt/core.h" +#include "fmt/core.h" // for format #endif -#include "picohttpparser.h" +#include "picohttpparser.h" // for phr_header namespace bell { class HTTPClient { @@ -31,19 +27,20 @@ class HTTPClient { // Helper over ValueHeader, formatting a HTTP bytes range struct RangeHeader { static ValueHeader range(int32_t from, int32_t to) { -#ifndef BELL_DISABLE_FMT +#ifndef BELL_DISABLE_FMT return ValueHeader{"Range", fmt::format("bytes={}-{}", from, to)}; -#else - return ValueHeader{"Range", "bytes=" + std::to_string(from) + "-" + std::to_string(to)}; -#endif +#else + return ValueHeader{ + "Range", "bytes=" + std::to_string(from) + "-" + std::to_string(to)}; +#endif } static ValueHeader last(int32_t nbytes) { -#ifndef BELL_DISABLE_FMT +#ifndef BELL_DISABLE_FMT return ValueHeader{"Range", fmt::format("bytes=-{}", nbytes)}; -#else +#else return ValueHeader{"Range", "bytes=-" + std::to_string(nbytes)}; -#endif +#endif } }; diff --git a/components/spotify/cspot/bell/main/io/include/SocketStream.h b/components/spotify/cspot/bell/main/io/include/SocketStream.h index 3b7030f1..7ed6770f 100644 --- a/components/spotify/cspot/bell/main/io/include/SocketStream.h +++ b/components/spotify/cspot/bell/main/io/include/SocketStream.h @@ -1,8 +1,10 @@ #pragma once -#include -#include "TCPSocket.h" -#include "TLSSocket.h" +#include // for streamsize, basic_streambuf<>::int_type, ios... +#include // for unique_ptr, operator!= +#include // for char_traits, string + +#include "BellSocket.h" // for Socket namespace bell { class SocketBuffer : public std::streambuf { diff --git a/components/spotify/cspot/bell/main/io/include/TCPSocket.h b/components/spotify/cspot/bell/main/io/include/TCPSocket.h index e28f0e76..73ae6ebf 100644 --- a/components/spotify/cspot/bell/main/io/include/TCPSocket.h +++ b/components/spotify/cspot/bell/main/io/include/TCPSocket.h @@ -39,6 +39,8 @@ class TCPSocket : public bell::Socket { TCPSocket(){}; ~TCPSocket() { close(); }; + int getFd() { return sockFd; } + void open(const std::string& host, uint16_t port) { int err; int domain = AF_INET; @@ -101,7 +103,9 @@ class TCPSocket : public bell::Socket { #endif return value; } - bool isOpen() { return !isClosed; } + bool isOpen() { + return !isClosed; + } void close() { if (!isClosed) { diff --git a/components/spotify/cspot/bell/main/io/include/TLSSocket.h b/components/spotify/cspot/bell/main/io/include/TLSSocket.h index e3d5f6a0..c3c43a5c 100644 --- a/components/spotify/cspot/bell/main/io/include/TLSSocket.h +++ b/components/spotify/cspot/bell/main/io/include/TLSSocket.h @@ -1,34 +1,21 @@ #ifndef BELL_TLS_SOCKET_H #define BELL_TLS_SOCKET_H -#include -#include -#include -#include -#include -#include "BellLogger.h" -#include "BellSocket.h" +#include // for uint8_t, uint16_t + +#include "BellSocket.h" // for Socket #ifdef _WIN32 #include #include #else -#include -#include -#include -#include -#include #endif -#include -#include -#include -#include -#include +#include // for size_t +#include // for string -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/debug.h" -#include "mbedtls/entropy.h" -#include "mbedtls/net_sockets.h" -#include "mbedtls/ssl.h" +#include "mbedtls/ctr_drbg.h" // for mbedtls_ctr_drbg_context +#include "mbedtls/entropy.h" // for mbedtls_entropy_context +#include "mbedtls/net_sockets.h" // for mbedtls_net_context +#include "mbedtls/ssl.h" // for mbedtls_ssl_config, mbedtls_ssl_con... namespace bell { class TLSSocket : public bell::Socket { @@ -53,6 +40,7 @@ class TLSSocket : public bell::Socket { bool isOpen(); void close(); + int getFd() { return server_fd.fd; } }; } // namespace bell diff --git a/components/spotify/cspot/bell/main/io/include/URLParser.h b/components/spotify/cspot/bell/main/io/include/URLParser.h index 3778c91b..98a59929 100644 --- a/components/spotify/cspot/bell/main/io/include/URLParser.h +++ b/components/spotify/cspot/bell/main/io/include/URLParser.h @@ -1,9 +1,9 @@ #pragma once -#include -#include -#include -#include +#include // for strtol, size_t +#include // for match_results, match_results<>::value_type, sub... +#include // for invalid_argument +#include // for string, allocator, operator+, char_traits, oper... namespace bell { class URLParser { @@ -60,7 +60,7 @@ class URLParser { std::string path; #ifdef BELL_DISABLE_REGEX void parse(const char* url, std::vector& match); -#else +#else static const std::regex urlParseRegex; #endif @@ -71,10 +71,10 @@ class URLParser { #ifdef BELL_DISABLE_REGEX std::vector match(6); parser.parse(url.c_str(), match); -#else +#else std::cmatch match; std::regex_match(url.c_str(), match, parser.urlParseRegex); -#endif +#endif if (match.size() < 3) { throw std::invalid_argument("Invalid URL"); diff --git a/components/spotify/cspot/bell/main/io/include/X509Bundle.h b/components/spotify/cspot/bell/main/io/include/X509Bundle.h index d9ed17cd..118dbcdc 100644 --- a/components/spotify/cspot/bell/main/io/include/X509Bundle.h +++ b/components/spotify/cspot/bell/main/io/include/X509Bundle.h @@ -1,8 +1,11 @@ #pragma once -#include -#include "BellLogger.h" -#include "mbedtls/ssl.h" +#include // for mbedtls_x509_crt +#include // for size_t +#include // for uint8_t, uint16_t, uint32_t +#include // for vector + +#include "mbedtls/ssl.h" // for mbedtls_ssl_config namespace bell::X509Bundle { @@ -13,6 +16,7 @@ typedef struct crt_bundle_t { } crt_bundle_t; static crt_bundle_t s_crt_bundle; +static std::vector bundleBytes; static constexpr auto TAG = "X509Bundle"; static constexpr auto CRT_HEADER_OFFSET = 4; diff --git a/components/spotify/cspot/bell/main/io/include/picohttpparser.h b/components/spotify/cspot/bell/main/io/include/picohttpparser.h index 2c685928..b0f663e6 100644 --- a/components/spotify/cspot/bell/main/io/include/picohttpparser.h +++ b/components/spotify/cspot/bell/main/io/include/picohttpparser.h @@ -40,30 +40,35 @@ extern "C" { /* contains name and value of a header (name == NULL if is a continuing line * of a multiline header */ struct phr_header { - const char *name; - size_t name_len; - const char *value; - size_t value_len; + const char* name; + size_t name_len; + const char* value; + size_t value_len; }; /* returns number of bytes consumed if successful, -2 if request is partial, * -1 if failed */ -int phr_parse_request(const char *buf, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len, - int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len); +int phr_parse_request(const char* buf, size_t len, const char** method, + size_t* method_len, const char** path, size_t* path_len, + int* minor_version, struct phr_header* headers, + size_t* num_headers, size_t last_len); /* ditto */ -int phr_parse_response(const char *_buf, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, - struct phr_header *headers, size_t *num_headers, size_t last_len); +int phr_parse_response(const char* _buf, size_t len, int* minor_version, + int* status, const char** msg, size_t* msg_len, + struct phr_header* headers, size_t* num_headers, + size_t last_len); /* ditto */ -int phr_parse_headers(const char *buf, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len); +int phr_parse_headers(const char* buf, size_t len, struct phr_header* headers, + size_t* num_headers, size_t last_len); /* should be zero-filled before start */ struct phr_chunked_decoder { - size_t bytes_left_in_chunk; /* number of bytes left in current chunk */ - char consume_trailer; /* if trailing headers should be consumed */ - char _hex_count; - char _state; + size_t bytes_left_in_chunk; /* number of bytes left in current chunk */ + char consume_trailer; /* if trailing headers should be consumed */ + char _hex_count; + char _state; }; /* the function rewrites the buffer given as (buf, bufsz) removing the chunked- @@ -75,10 +80,11 @@ struct phr_chunked_decoder { * octets left undecoded, that starts from the offset returned by `*bufsz`. * Returns -1 on error. */ -ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *bufsz); +ssize_t phr_decode_chunked(struct phr_chunked_decoder* decoder, char* buf, + size_t* bufsz); /* returns if the chunked decoder is in middle of chunked data */ -int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder); +int phr_decode_chunked_is_in_data(struct phr_chunked_decoder* decoder); #ifdef __cplusplus } diff --git a/components/spotify/cspot/bell/main/io/picohttpparser.c b/components/spotify/cspot/bell/main/io/picohttpparser.c index 5e5783ab..b4070466 100644 --- a/components/spotify/cspot/bell/main/io/picohttpparser.c +++ b/components/spotify/cspot/bell/main/io/picohttpparser.c @@ -24,9 +24,10 @@ * IN THE SOFTWARE. */ -#include -#include -#include +#include // for assert +#include // for NULL, size_t +#include // for memmove +#include // for ssize_t #ifdef __SSE4_2__ #ifdef _MSC_VER #include @@ -34,7 +35,7 @@ #include #endif #endif -#include "picohttpparser.h" +#include "picohttpparser.h" // for phr_chunked_decoder, phr_header, phr_dec... #if __GNUC__ >= 3 #define likely(x) __builtin_expect(!!(x), 1) @@ -52,612 +53,634 @@ #define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u) -#define CHECK_EOF() \ - if (buf == buf_end) { \ - *ret = -2; \ - return NULL; \ - } +#define CHECK_EOF() \ + if (buf == buf_end) { \ + *ret = -2; \ + return NULL; \ + } -#define EXPECT_CHAR_NO_CHECK(ch) \ - if (*buf++ != ch) { \ - *ret = -1; \ - return NULL; \ - } +#define EXPECT_CHAR_NO_CHECK(ch) \ + if (*buf++ != ch) { \ + *ret = -1; \ + return NULL; \ + } -#define EXPECT_CHAR(ch) \ - CHECK_EOF(); \ - EXPECT_CHAR_NO_CHECK(ch); +#define EXPECT_CHAR(ch) \ + CHECK_EOF(); \ + EXPECT_CHAR_NO_CHECK(ch); -#define ADVANCE_TOKEN(tok, toklen) \ - do { \ - const char *tok_start = buf; \ - static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \ - int found2; \ - buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \ - if (!found2) { \ - CHECK_EOF(); \ - } \ - while (1) { \ - if (*buf == ' ') { \ - break; \ - } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ - if ((unsigned char)*buf < '\040' || *buf == '\177') { \ - *ret = -1; \ - return NULL; \ - } \ - } \ - ++buf; \ - CHECK_EOF(); \ - } \ - tok = tok_start; \ - toklen = buf - tok_start; \ - } while (0) +#define ADVANCE_TOKEN(tok, toklen) \ + do { \ + const char* tok_start = buf; \ + static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \ + int found2; \ + buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \ + if (!found2) { \ + CHECK_EOF(); \ + } \ + while (1) { \ + if (*buf == ' ') { \ + break; \ + } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ + if ((unsigned char)*buf < '\040' || *buf == '\177') { \ + *ret = -1; \ + return NULL; \ + } \ + } \ + ++buf; \ + CHECK_EOF(); \ + } \ + tok = tok_start; \ + toklen = buf - tok_start; \ + } while (0) -static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" - "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" - "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +static const char* token_char_map = + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" + "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" + "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; -static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) -{ - *found = 0; +static const char* findchar_fast(const char* buf, const char* buf_end, + const char* ranges, size_t ranges_size, + int* found) { + *found = 0; #if __SSE4_2__ - if (likely(buf_end - buf >= 16)) { - __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges); + if (likely(buf_end - buf >= 16)) { + __m128i ranges16 = _mm_loadu_si128((const __m128i*)ranges); - size_t left = (buf_end - buf) & ~15; - do { - __m128i b16 = _mm_loadu_si128((const __m128i *)buf); - int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); - if (unlikely(r != 16)) { - buf += r; - *found = 1; - break; - } - buf += 16; - left -= 16; - } while (likely(left != 0)); - } + size_t left = (buf_end - buf) & ~15; + do { + __m128i b16 = _mm_loadu_si128((const __m128i*)buf); + int r = _mm_cmpestri( + ranges16, ranges_size, b16, 16, + _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); + if (unlikely(r != 16)) { + buf += r; + *found = 1; + break; + } + buf += 16; + left -= 16; + } while (likely(left != 0)); + } #else - /* suppress unused parameter warning */ - (void)buf_end; - (void)ranges; - (void)ranges_size; + /* suppress unused parameter warning */ + (void)buf_end; + (void)ranges; + (void)ranges_size; #endif - return buf; + return buf; } -static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) -{ - const char *token_start = buf; +static const char* get_token_to_eol(const char* buf, const char* buf_end, + const char** token, size_t* token_len, + int* ret) { + const char* token_start = buf; #ifdef __SSE4_2__ - static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */ - "\012\037" /* allow SP and up to but not including DEL */ - "\177\177"; /* allow chars w. MSB set */ - int found; - buf = findchar_fast(buf, buf_end, ranges1, 6, &found); - if (found) - goto FOUND_CTL; + static const char ALIGNED(16) ranges1[16] = + "\0\010" /* allow HT */ + "\012\037" /* allow SP and up to but not including DEL */ + "\177\177"; /* allow chars w. MSB set */ + int found; + buf = findchar_fast(buf, buf_end, ranges1, 6, &found); + if (found) + goto FOUND_CTL; #else - /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ - while (likely(buf_end - buf >= 8)) { -#define DOIT() \ - do { \ - if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ - goto NonPrintable; \ - ++buf; \ - } while (0) - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); - DOIT(); + /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ + while (likely(buf_end - buf >= 8)) { +#define DOIT() \ + do { \ + if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ + goto NonPrintable; \ + ++buf; \ + } while (0) + DOIT(); + DOIT(); + DOIT(); + DOIT(); + DOIT(); + DOIT(); + DOIT(); + DOIT(); #undef DOIT - continue; - NonPrintable: - if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { - goto FOUND_CTL; - } - ++buf; + continue; + NonPrintable: + if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || + unlikely(*buf == '\177')) { + goto FOUND_CTL; } + ++buf; + } #endif - for (;; ++buf) { - CHECK_EOF(); - if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { - if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { - goto FOUND_CTL; - } - } + for (;; ++buf) { + CHECK_EOF(); + if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { + if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || + unlikely(*buf == '\177')) { + goto FOUND_CTL; + } } + } FOUND_CTL: - if (likely(*buf == '\015')) { - ++buf; - EXPECT_CHAR('\012'); - *token_len = buf - 2 - token_start; - } else if (*buf == '\012') { - *token_len = buf - token_start; - ++buf; - } else { - *ret = -1; - return NULL; - } - *token = token_start; - - return buf; -} - -static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) -{ - int ret_cnt = 0; - buf = last_len < 3 ? buf : buf + last_len - 3; - - while (1) { - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - CHECK_EOF(); - EXPECT_CHAR('\012'); - ++ret_cnt; - } else if (*buf == '\012') { - ++buf; - ++ret_cnt; - } else { - ++buf; - ret_cnt = 0; - } - if (ret_cnt == 2) { - return buf; - } - } - - *ret = -2; + if (likely(*buf == '\015')) { + ++buf; + EXPECT_CHAR('\012'); + *token_len = buf - 2 - token_start; + } else if (*buf == '\012') { + *token_len = buf - token_start; + ++buf; + } else { + *ret = -1; return NULL; + } + *token = token_start; + + return buf; } -#define PARSE_INT(valp_, mul_) \ - if (*buf < '0' || '9' < *buf) { \ - buf++; \ - *ret = -1; \ - return NULL; \ - } \ - *(valp_) = (mul_) * (*buf++ - '0'); +static const char* is_complete(const char* buf, const char* buf_end, + size_t last_len, int* ret) { + int ret_cnt = 0; + buf = last_len < 3 ? buf : buf + last_len - 3; -#define PARSE_INT_3(valp_) \ - do { \ - int res_ = 0; \ - PARSE_INT(&res_, 100) \ - *valp_ = res_; \ - PARSE_INT(&res_, 10) \ - *valp_ += res_; \ - PARSE_INT(&res_, 1) \ - *valp_ += res_; \ - } while (0) - -/* returned pointer is always within [buf, buf_end), or null */ -static const char *parse_token(const char *buf, const char *buf_end, const char **token, size_t *token_len, char next_char, - int *ret) -{ - /* We use pcmpestri to detect non-token characters. This instruction can take no more than eight character ranges (8*2*8=128 - * bits that is the size of a SSE register). Due to this restriction, characters `|` and `~` are handled in the slow loop. */ - static const char ALIGNED(16) ranges[] = "\x00 " /* control chars and up to SP */ - "\"\"" /* 0x22 */ - "()" /* 0x28,0x29 */ - ",," /* 0x2c */ - "//" /* 0x2f */ - ":@" /* 0x3a-0x40 */ - "[]" /* 0x5b-0x5d */ - "{\xff"; /* 0x7b-0xff */ - const char *buf_start = buf; - int found; - buf = findchar_fast(buf, buf_end, ranges, sizeof(ranges) - 1, &found); - if (!found) { - CHECK_EOF(); - } - while (1) { - if (*buf == next_char) { - break; - } else if (!token_char_map[(unsigned char)*buf]) { - *ret = -1; - return NULL; - } - ++buf; - CHECK_EOF(); - } - *token = buf_start; - *token_len = buf - buf_start; - return buf; -} - -/* returned pointer is always within [buf, buf_end), or null */ -static const char *parse_http_version(const char *buf, const char *buf_end, int *minor_version, int *ret) -{ - /* we want at least [HTTP/1.] to try to parse */ - if (buf_end - buf < 9) { - *ret = -2; - return NULL; - } - EXPECT_CHAR_NO_CHECK('H'); - EXPECT_CHAR_NO_CHECK('T'); - EXPECT_CHAR_NO_CHECK('T'); - EXPECT_CHAR_NO_CHECK('P'); - EXPECT_CHAR_NO_CHECK('/'); - EXPECT_CHAR_NO_CHECK('1'); - EXPECT_CHAR_NO_CHECK('.'); - PARSE_INT(minor_version, 1); - return buf; -} - -static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, - size_t max_headers, int *ret) -{ - for (;; ++*num_headers) { - CHECK_EOF(); - if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); - break; - } else if (*buf == '\012') { - ++buf; - break; - } - if (*num_headers == max_headers) { - *ret = -1; - return NULL; - } - if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { - /* parsing name, but do not discard SP before colon, see - * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ - if ((buf = parse_token(buf, buf_end, &headers[*num_headers].name, &headers[*num_headers].name_len, ':', ret)) == NULL) { - return NULL; - } - if (headers[*num_headers].name_len == 0) { - *ret = -1; - return NULL; - } - ++buf; - for (;; ++buf) { - CHECK_EOF(); - if (!(*buf == ' ' || *buf == '\t')) { - break; - } - } - } else { - headers[*num_headers].name = NULL; - headers[*num_headers].name_len = 0; - } - const char *value; - size_t value_len; - if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) { - return NULL; - } - /* remove trailing SPs and HTABs */ - const char *value_end = value + value_len; - for (; value_end != value; --value_end) { - const char c = *(value_end - 1); - if (!(c == ' ' || c == '\t')) { - break; - } - } - headers[*num_headers].value = value; - headers[*num_headers].value_len = value_end - value; - } - return buf; -} - -static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, - size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, - size_t max_headers, int *ret) -{ - /* skip first empty line (some clients add CRLF after POST content) */ + while (1) { CHECK_EOF(); if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); + ++buf; + CHECK_EOF(); + EXPECT_CHAR('\012'); + ++ret_cnt; } else if (*buf == '\012') { - ++buf; + ++buf; + ++ret_cnt; + } else { + ++buf; + ret_cnt = 0; } + if (ret_cnt == 2) { + return buf; + } + } - /* parse request line */ - if ((buf = parse_token(buf, buf_end, method, method_len, ' ', ret)) == NULL) { - return NULL; - } - do { - ++buf; - CHECK_EOF(); - } while (*buf == ' '); - ADVANCE_TOKEN(*path, *path_len); - do { - ++buf; - CHECK_EOF(); - } while (*buf == ' '); - if (*method_len == 0 || *path_len == 0) { - *ret = -1; - return NULL; - } - if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { - return NULL; + *ret = -2; + return NULL; +} + +#define PARSE_INT(valp_, mul_) \ + if (*buf < '0' || '9' < *buf) { \ + buf++; \ + *ret = -1; \ + return NULL; \ + } \ + *(valp_) = (mul_) * (*buf++ - '0'); + +#define PARSE_INT_3(valp_) \ + do { \ + int res_ = 0; \ + PARSE_INT(&res_, 100) \ + *valp_ = res_; \ + PARSE_INT(&res_, 10) \ + *valp_ += res_; \ + PARSE_INT(&res_, 1) \ + *valp_ += res_; \ + } while (0) + +/* returned pointer is always within [buf, buf_end), or null */ +static const char* parse_token(const char* buf, const char* buf_end, + const char** token, size_t* token_len, + char next_char, int* ret) { + /* We use pcmpestri to detect non-token characters. This instruction can take no more than eight character ranges (8*2*8=128 + * bits that is the size of a SSE register). Due to this restriction, characters `|` and `~` are handled in the slow loop. */ + static const char ALIGNED(16) ranges[] = + "\x00 " /* control chars and up to SP */ + "\"\"" /* 0x22 */ + "()" /* 0x28,0x29 */ + ",," /* 0x2c */ + "//" /* 0x2f */ + ":@" /* 0x3a-0x40 */ + "[]" /* 0x5b-0x5d */ + "{\xff"; /* 0x7b-0xff */ + const char* buf_start = buf; + int found; + buf = findchar_fast(buf, buf_end, ranges, sizeof(ranges) - 1, &found); + if (!found) { + CHECK_EOF(); + } + while (1) { + if (*buf == next_char) { + break; + } else if (!token_char_map[(unsigned char)*buf]) { + *ret = -1; + return NULL; } + ++buf; + CHECK_EOF(); + } + *token = buf_start; + *token_len = buf - buf_start; + return buf; +} + +/* returned pointer is always within [buf, buf_end), or null */ +static const char* parse_http_version(const char* buf, const char* buf_end, + int* minor_version, int* ret) { + /* we want at least [HTTP/1.] to try to parse */ + if (buf_end - buf < 9) { + *ret = -2; + return NULL; + } + EXPECT_CHAR_NO_CHECK('H'); + EXPECT_CHAR_NO_CHECK('T'); + EXPECT_CHAR_NO_CHECK('T'); + EXPECT_CHAR_NO_CHECK('P'); + EXPECT_CHAR_NO_CHECK('/'); + EXPECT_CHAR_NO_CHECK('1'); + EXPECT_CHAR_NO_CHECK('.'); + PARSE_INT(minor_version, 1); + return buf; +} + +static const char* parse_headers(const char* buf, const char* buf_end, + struct phr_header* headers, + size_t* num_headers, size_t max_headers, + int* ret) { + for (;; ++*num_headers) { + CHECK_EOF(); if (*buf == '\015') { - ++buf; - EXPECT_CHAR('\012'); + ++buf; + EXPECT_CHAR('\012'); + break; } else if (*buf == '\012') { - ++buf; - } else { + ++buf; + break; + } + if (*num_headers == max_headers) { + *ret = -1; + return NULL; + } + if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { + /* parsing name, but do not discard SP before colon, see + * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ + if ((buf = parse_token(buf, buf_end, &headers[*num_headers].name, + &headers[*num_headers].name_len, ':', ret)) == + NULL) { + return NULL; + } + if (headers[*num_headers].name_len == 0) { *ret = -1; return NULL; - } - - return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); -} - -int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, - size_t *path_len, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf_start + len; - size_t max_headers = *num_headers; - int r; - - *method = NULL; - *method_len = 0; - *path = NULL; - *path_len = 0; - *minor_version = -1; - *num_headers = 0; - - /* if last_len != 0, check if the request is complete (a fast countermeasure - againt slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, minor_version, headers, num_headers, max_headers, - &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); -} - -static const char *parse_response(const char *buf, const char *buf_end, int *minor_version, int *status, const char **msg, - size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) -{ - /* parse "HTTP/1.x" */ - if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { - return NULL; - } - /* skip space */ - if (*buf != ' ') { - *ret = -1; - return NULL; - } - do { - ++buf; + } + ++buf; + for (;; ++buf) { CHECK_EOF(); - } while (*buf == ' '); - /* parse status code, we want at least [:digit:][:digit:][:digit:] to try to parse */ - if (buf_end - buf < 4) { - *ret = -2; - return NULL; - } - PARSE_INT_3(status); - - /* get message including preceding space */ - if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { - return NULL; - } - if (*msg_len == 0) { - /* ok */ - } else if (**msg == ' ') { - /* Remove preceding space. Successful return from `get_token_to_eol` guarantees that we would hit something other than SP - * before running past the end of the given buffer. */ - do { - ++*msg; - --*msg_len; - } while (**msg == ' '); + if (!(*buf == ' ' || *buf == '\t')) { + break; + } + } } else { - /* garbage found after status code */ - *ret = -1; - return NULL; + headers[*num_headers].name = NULL; + headers[*num_headers].name_len = 0; } - - return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); + const char* value; + size_t value_len; + if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == + NULL) { + return NULL; + } + /* remove trailing SPs and HTABs */ + const char* value_end = value + value_len; + for (; value_end != value; --value_end) { + const char c = *(value_end - 1); + if (!(c == ' ' || c == '\t')) { + break; + } + } + headers[*num_headers].value = value; + headers[*num_headers].value_len = value_end - value; + } + return buf; } -int phr_parse_response(const char *buf_start, size_t len, int *minor_version, int *status, const char **msg, size_t *msg_len, - struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; +static const char* parse_request(const char* buf, const char* buf_end, + const char** method, size_t* method_len, + const char** path, size_t* path_len, + int* minor_version, struct phr_header* headers, + size_t* num_headers, size_t max_headers, + int* ret) { + /* skip first empty line (some clients add CRLF after POST content) */ + CHECK_EOF(); + if (*buf == '\015') { + ++buf; + EXPECT_CHAR('\012'); + } else if (*buf == '\012') { + ++buf; + } - *minor_version = -1; - *status = 0; - *msg = NULL; - *msg_len = 0; - *num_headers = 0; + /* parse request line */ + if ((buf = parse_token(buf, buf_end, method, method_len, ' ', ret)) == NULL) { + return NULL; + } + do { + ++buf; + CHECK_EOF(); + } while (*buf == ' '); + ADVANCE_TOKEN(*path, *path_len); + do { + ++buf; + CHECK_EOF(); + } while (*buf == ' '); + if (*method_len == 0 || *path_len == 0) { + *ret = -1; + return NULL; + } + if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { + return NULL; + } + if (*buf == '\015') { + ++buf; + EXPECT_CHAR('\012'); + } else if (*buf == '\012') { + ++buf; + } else { + *ret = -1; + return NULL; + } - /* if last_len != 0, check if the response is complete (a fast countermeasure - against slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } - - if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) { - return r; - } - - return (int)(buf - buf_start); + return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); } -int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) -{ - const char *buf = buf_start, *buf_end = buf + len; - size_t max_headers = *num_headers; - int r; +int phr_parse_request(const char* buf_start, size_t len, const char** method, + size_t* method_len, const char** path, size_t* path_len, + int* minor_version, struct phr_header* headers, + size_t* num_headers, size_t last_len) { + const char *buf = buf_start, *buf_end = buf_start + len; + size_t max_headers = *num_headers; + int r; - *num_headers = 0; + *method = NULL; + *method_len = 0; + *path = NULL; + *path_len = 0; + *minor_version = -1; + *num_headers = 0; - /* if last_len != 0, check if the response is complete (a fast countermeasure + /* if last_len != 0, check if the request is complete (a fast countermeasure + againt slowloris */ + if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { + return r; + } + + if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, + minor_version, headers, num_headers, max_headers, + &r)) == NULL) { + return r; + } + + return (int)(buf - buf_start); +} + +static const char* parse_response(const char* buf, const char* buf_end, + int* minor_version, int* status, + const char** msg, size_t* msg_len, + struct phr_header* headers, + size_t* num_headers, size_t max_headers, + int* ret) { + /* parse "HTTP/1.x" */ + if ((buf = parse_http_version(buf, buf_end, minor_version, ret)) == NULL) { + return NULL; + } + /* skip space */ + if (*buf != ' ') { + *ret = -1; + return NULL; + } + do { + ++buf; + CHECK_EOF(); + } while (*buf == ' '); + /* parse status code, we want at least [:digit:][:digit:][:digit:] to try to parse */ + if (buf_end - buf < 4) { + *ret = -2; + return NULL; + } + PARSE_INT_3(status); + + /* get message including preceding space */ + if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { + return NULL; + } + if (*msg_len == 0) { + /* ok */ + } else if (**msg == ' ') { + /* Remove preceding space. Successful return from `get_token_to_eol` guarantees that we would hit something other than SP + * before running past the end of the given buffer. */ + do { + ++*msg; + --*msg_len; + } while (**msg == ' '); + } else { + /* garbage found after status code */ + *ret = -1; + return NULL; + } + + return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); +} + +int phr_parse_response(const char* buf_start, size_t len, int* minor_version, + int* status, const char** msg, size_t* msg_len, + struct phr_header* headers, size_t* num_headers, + size_t last_len) { + const char *buf = buf_start, *buf_end = buf + len; + size_t max_headers = *num_headers; + int r; + + *minor_version = -1; + *status = 0; + *msg = NULL; + *msg_len = 0; + *num_headers = 0; + + /* if last_len != 0, check if the response is complete (a fast countermeasure against slowloris */ - if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { - return r; - } + if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { + return r; + } - if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) { - return r; - } + if ((buf = parse_response(buf, buf_end, minor_version, status, msg, msg_len, + headers, num_headers, max_headers, &r)) == NULL) { + return r; + } - return (int)(buf - buf_start); + return (int)(buf - buf_start); +} + +int phr_parse_headers(const char* buf_start, size_t len, + struct phr_header* headers, size_t* num_headers, + size_t last_len) { + const char *buf = buf_start, *buf_end = buf + len; + size_t max_headers = *num_headers; + int r; + + *num_headers = 0; + + /* if last_len != 0, check if the response is complete (a fast countermeasure + against slowloris */ + if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { + return r; + } + + if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, + &r)) == NULL) { + return r; + } + + return (int)(buf - buf_start); } enum { - CHUNKED_IN_CHUNK_SIZE, - CHUNKED_IN_CHUNK_EXT, - CHUNKED_IN_CHUNK_DATA, - CHUNKED_IN_CHUNK_CRLF, - CHUNKED_IN_TRAILERS_LINE_HEAD, - CHUNKED_IN_TRAILERS_LINE_MIDDLE + CHUNKED_IN_CHUNK_SIZE, + CHUNKED_IN_CHUNK_EXT, + CHUNKED_IN_CHUNK_DATA, + CHUNKED_IN_CHUNK_CRLF, + CHUNKED_IN_TRAILERS_LINE_HEAD, + CHUNKED_IN_TRAILERS_LINE_MIDDLE }; -static int decode_hex(int ch) -{ - if ('0' <= ch && ch <= '9') { - return ch - '0'; - } else if ('A' <= ch && ch <= 'F') { - return ch - 'A' + 0xa; - } else if ('a' <= ch && ch <= 'f') { - return ch - 'a' + 0xa; - } else { - return -1; - } +static int decode_hex(int ch) { + if ('0' <= ch && ch <= '9') { + return ch - '0'; + } else if ('A' <= ch && ch <= 'F') { + return ch - 'A' + 0xa; + } else if ('a' <= ch && ch <= 'f') { + return ch - 'a' + 0xa; + } else { + return -1; + } } -ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) -{ - size_t dst = 0, src = 0, bufsz = *_bufsz; - ssize_t ret = -2; /* incomplete */ +ssize_t phr_decode_chunked(struct phr_chunked_decoder* decoder, char* buf, + size_t* _bufsz) { + size_t dst = 0, src = 0, bufsz = *_bufsz; + ssize_t ret = -2; /* incomplete */ - while (1) { - switch (decoder->_state) { - case CHUNKED_IN_CHUNK_SIZE: - for (;; ++src) { - int v; - if (src == bufsz) - goto Exit; - if ((v = decode_hex(buf[src])) == -1) { - if (decoder->_hex_count == 0) { - ret = -1; - goto Exit; - } - break; - } - if (decoder->_hex_count == sizeof(size_t) * 2) { - ret = -1; - goto Exit; - } - decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; - ++decoder->_hex_count; + while (1) { + switch (decoder->_state) { + case CHUNKED_IN_CHUNK_SIZE: + for (;; ++src) { + int v; + if (src == bufsz) + goto Exit; + if ((v = decode_hex(buf[src])) == -1) { + if (decoder->_hex_count == 0) { + ret = -1; + goto Exit; } - decoder->_hex_count = 0; - decoder->_state = CHUNKED_IN_CHUNK_EXT; - /* fallthru */ - case CHUNKED_IN_CHUNK_EXT: - /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; - if (decoder->bytes_left_in_chunk == 0) { - if (decoder->consume_trailer) { - decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; - break; - } else { - goto Complete; - } - } - decoder->_state = CHUNKED_IN_CHUNK_DATA; - /* fallthru */ - case CHUNKED_IN_CHUNK_DATA: { - size_t avail = bufsz - src; - if (avail < decoder->bytes_left_in_chunk) { - if (dst != src) - memmove(buf + dst, buf + src, avail); - src += avail; - dst += avail; - decoder->bytes_left_in_chunk -= avail; - goto Exit; - } - if (dst != src) - memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); - src += decoder->bytes_left_in_chunk; - dst += decoder->bytes_left_in_chunk; - decoder->bytes_left_in_chunk = 0; - decoder->_state = CHUNKED_IN_CHUNK_CRLF; - } - /* fallthru */ - case CHUNKED_IN_CHUNK_CRLF: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src] != '\012') { - ret = -1; - goto Exit; - } - ++src; - decoder->_state = CHUNKED_IN_CHUNK_SIZE; break; - case CHUNKED_IN_TRAILERS_LINE_HEAD: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] != '\015') - break; - } - if (buf[src++] == '\012') - goto Complete; - decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; - /* fallthru */ - case CHUNKED_IN_TRAILERS_LINE_MIDDLE: - for (;; ++src) { - if (src == bufsz) - goto Exit; - if (buf[src] == '\012') - break; - } - ++src; + } + if (decoder->_hex_count == sizeof(size_t) * 2) { + ret = -1; + goto Exit; + } + decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; + ++decoder->_hex_count; + } + decoder->_hex_count = 0; + decoder->_state = CHUNKED_IN_CHUNK_EXT; + /* fallthru */ + case CHUNKED_IN_CHUNK_EXT: + /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] == '\012') + break; + } + ++src; + if (decoder->bytes_left_in_chunk == 0) { + if (decoder->consume_trailer) { decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; break; - default: - assert(!"decoder is corrupt"); + } else { + goto Complete; + } } + decoder->_state = CHUNKED_IN_CHUNK_DATA; + /* fallthru */ + case CHUNKED_IN_CHUNK_DATA: { + size_t avail = bufsz - src; + if (avail < decoder->bytes_left_in_chunk) { + if (dst != src) + memmove(buf + dst, buf + src, avail); + src += avail; + dst += avail; + decoder->bytes_left_in_chunk -= avail; + goto Exit; + } + if (dst != src) + memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); + src += decoder->bytes_left_in_chunk; + dst += decoder->bytes_left_in_chunk; + decoder->bytes_left_in_chunk = 0; + decoder->_state = CHUNKED_IN_CHUNK_CRLF; + } + /* fallthru */ + case CHUNKED_IN_CHUNK_CRLF: + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] != '\015') + break; + } + if (buf[src] != '\012') { + ret = -1; + goto Exit; + } + ++src; + decoder->_state = CHUNKED_IN_CHUNK_SIZE; + break; + case CHUNKED_IN_TRAILERS_LINE_HEAD: + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] != '\015') + break; + } + if (buf[src++] == '\012') + goto Complete; + decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; + /* fallthru */ + case CHUNKED_IN_TRAILERS_LINE_MIDDLE: + for (;; ++src) { + if (src == bufsz) + goto Exit; + if (buf[src] == '\012') + break; + } + ++src; + decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; + break; + default: + assert(!"decoder is corrupt"); } + } Complete: - ret = bufsz - src; + ret = bufsz - src; Exit: - if (dst != src) - memmove(buf + dst, buf + src, bufsz - src); - *_bufsz = dst; - return ret; + if (dst != src) + memmove(buf + dst, buf + src, bufsz - src); + *_bufsz = dst; + return ret; } -int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) -{ - return decoder->_state == CHUNKED_IN_CHUNK_DATA; +int phr_decode_chunked_is_in_data(struct phr_chunked_decoder* decoder) { + return decoder->_state == CHUNKED_IN_CHUNK_DATA; } #undef CHECK_EOF diff --git a/components/spotify/cspot/bell/main/platform/MDNSService.h b/components/spotify/cspot/bell/main/platform/MDNSService.h index f7389a41..ad372314 100644 --- a/components/spotify/cspot/bell/main/platform/MDNSService.h +++ b/components/spotify/cspot/bell/main/platform/MDNSService.h @@ -1,23 +1,19 @@ #pragma once -#include -#include -#include +#include // for map +#include // for unique_ptr +#include // for string namespace bell { class MDNSService { -public: - virtual ~MDNSService() { } - static std::unique_ptr registerService( - const std::string &serviceName, - const std::string &serviceType, - const std::string &serviceProto, - const std::string &serviceHost, - int servicePort, - const std::map txtData - ); - virtual void unregisterService() = 0; + public: + virtual ~MDNSService() {} + static std::unique_ptr registerService( + const std::string& serviceName, const std::string& serviceType, + const std::string& serviceProto, const std::string& serviceHost, + int servicePort, const std::map txtData); + virtual void unregisterService() = 0; }; -} // namespace bell \ No newline at end of file +} // namespace bell \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/platform/WrappedSemaphore.h b/components/spotify/cspot/bell/main/platform/WrappedSemaphore.h index be27ac70..e6a5b264 100644 --- a/components/spotify/cspot/bell/main/platform/WrappedSemaphore.h +++ b/components/spotify/cspot/bell/main/platform/WrappedSemaphore.h @@ -4,7 +4,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #elif __APPLE__ -#include +#include // for dispatch_semaphore_t #elif _WIN32 #include #else @@ -15,24 +15,24 @@ namespace bell { class WrappedSemaphore { - private: + private: #ifdef ESP_PLATFORM - SemaphoreHandle_t semaphoreHandle; + SemaphoreHandle_t semaphoreHandle; #elif __APPLE__ - dispatch_semaphore_t semaphoreHandle; + dispatch_semaphore_t semaphoreHandle; #elif _WIN32 - HANDLE semaphoreHandle; + HANDLE semaphoreHandle; #else - sem_t semaphoreHandle; + sem_t semaphoreHandle; #endif - public: - WrappedSemaphore(int maxVal = 200); - ~WrappedSemaphore(); + public: + WrappedSemaphore(int maxVal = 200); + ~WrappedSemaphore(); - int wait(); - int twait(long milliseconds = 10); - void give(); + int wait(); + int twait(long milliseconds = 10); + void give(); }; -} // namespace bell +} // namespace bell diff --git a/components/spotify/cspot/bell/main/platform/apple/MDNSService.cpp b/components/spotify/cspot/bell/main/platform/apple/MDNSService.cpp index 1948302f..c872f656 100644 --- a/components/spotify/cspot/bell/main/platform/apple/MDNSService.cpp +++ b/components/spotify/cspot/bell/main/platform/apple/MDNSService.cpp @@ -1,16 +1,20 @@ #include "MDNSService.h" -#include "dns_sd.h" -#include + +#include // for NULL +#include // for pair + +#include "dns_sd.h" // for DNSServiceRef, DNSServiceRefDeallocate, DNS... +#include "i386/endian.h" // for htons using namespace bell; class implMDNSService : public MDNSService { -private: - DNSServiceRef* service; + private: + DNSServiceRef* service; -public: - implMDNSService(DNSServiceRef* service) : service(service) { } - void unregisterService() { DNSServiceRefDeallocate(*service); } + public: + implMDNSService(DNSServiceRef* service) : service(service) {} + void unregisterService() { DNSServiceRefDeallocate(*service); } }; /** @@ -18,33 +22,30 @@ public: * @see https://developer.apple.com/documentation/dnssd/1804733-dnsserviceregister **/ std::unique_ptr MDNSService::registerService( - const std::string& serviceName, - const std::string& serviceType, - const std::string& serviceProto, - const std::string& serviceHost, - int servicePort, - const std::map txtData -) { - DNSServiceRef* ref = new DNSServiceRef(); - TXTRecordRef txtRecord; - TXTRecordCreate(&txtRecord, 0, NULL); - for (auto& data : txtData) { - TXTRecordSetValue(&txtRecord, data.first.c_str(), data.second.size(), data.second.c_str()); - } - DNSServiceRegister( - ref, /* sdRef */ - 0, /* flags */ - 0, /* interfaceIndex */ - serviceName.c_str(), /* name */ - (serviceType + "." + serviceProto).c_str(), /* regType (_spotify-connect._tcp) */ - NULL, /* domain */ - NULL, /* host */ - htons(servicePort), /* port */ - TXTRecordGetLength(&txtRecord), /* txtLen */ - TXTRecordGetBytesPtr(&txtRecord), /* txtRecord */ - NULL, /* callBack */ - NULL /* context */ - ); - TXTRecordDeallocate(&txtRecord); - return std::make_unique(ref); -} \ No newline at end of file + const std::string& serviceName, const std::string& serviceType, + const std::string& serviceProto, const std::string& serviceHost, + int servicePort, const std::map txtData) { + DNSServiceRef* ref = new DNSServiceRef(); + TXTRecordRef txtRecord; + TXTRecordCreate(&txtRecord, 0, NULL); + for (auto& data : txtData) { + TXTRecordSetValue(&txtRecord, data.first.c_str(), data.second.size(), + data.second.c_str()); + } + DNSServiceRegister(ref, /* sdRef */ + 0, /* flags */ + 0, /* interfaceIndex */ + serviceName.c_str(), /* name */ + (serviceType + "." + serviceProto) + .c_str(), /* regType (_spotify-connect._tcp) */ + NULL, /* domain */ + NULL, /* host */ + htons(servicePort), /* port */ + TXTRecordGetLength(&txtRecord), /* txtLen */ + TXTRecordGetBytesPtr(&txtRecord), /* txtRecord */ + NULL, /* callBack */ + NULL /* context */ + ); + TXTRecordDeallocate(&txtRecord); + return std::make_unique(ref); +} diff --git a/components/spotify/cspot/bell/main/platform/apple/WrappedSemaphore.cpp b/components/spotify/cspot/bell/main/platform/apple/WrappedSemaphore.cpp index 505f974b..4fc146ff 100644 --- a/components/spotify/cspot/bell/main/platform/apple/WrappedSemaphore.cpp +++ b/components/spotify/cspot/bell/main/platform/apple/WrappedSemaphore.cpp @@ -2,30 +2,26 @@ using namespace bell; -WrappedSemaphore::WrappedSemaphore(int count) -{ - semaphoreHandle = dispatch_semaphore_create(0); +WrappedSemaphore::WrappedSemaphore(int count) { + semaphoreHandle = dispatch_semaphore_create(0); } -WrappedSemaphore::~WrappedSemaphore() -{ - dispatch_release(semaphoreHandle); +WrappedSemaphore::~WrappedSemaphore() { + dispatch_release(semaphoreHandle); } -int WrappedSemaphore::wait() -{ +int WrappedSemaphore::wait() { - return dispatch_semaphore_wait(semaphoreHandle, DISPATCH_TIME_FOREVER); + return dispatch_semaphore_wait(semaphoreHandle, DISPATCH_TIME_FOREVER); } -int WrappedSemaphore::twait(long milliseconds) -{ - dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (NSEC_PER_SEC / 1000) * milliseconds); +int WrappedSemaphore::twait(long milliseconds) { + dispatch_time_t timeout = + dispatch_time(DISPATCH_TIME_NOW, (NSEC_PER_SEC / 1000) * milliseconds); - return dispatch_semaphore_wait(semaphoreHandle, timeout); + return dispatch_semaphore_wait(semaphoreHandle, timeout); } -void WrappedSemaphore::give() -{ - dispatch_semaphore_signal(semaphoreHandle); +void WrappedSemaphore::give() { + dispatch_semaphore_signal(semaphoreHandle); } diff --git a/components/spotify/cspot/bell/main/platform/esp/MDNSService.cpp b/components/spotify/cspot/bell/main/platform/esp/MDNSService.cpp index 81f269cf..b568cecc 100644 --- a/components/spotify/cspot/bell/main/platform/esp/MDNSService.cpp +++ b/components/spotify/cspot/bell/main/platform/esp/MDNSService.cpp @@ -6,13 +6,14 @@ using namespace bell; class implMDNSService : public MDNSService { -private: - const std::string type; - const std::string proto; - void unregisterService() { mdns_service_remove(type.c_str(), proto.c_str()); } + private: + const std::string type; + const std::string proto; + void unregisterService() { mdns_service_remove(type.c_str(), proto.c_str()); } -public: - implMDNSService(std::string type, std::string proto) : type(type), proto(proto) { }; + public: + implMDNSService(std::string type, std::string proto) + : type(type), proto(proto){}; }; /** @@ -21,30 +22,25 @@ public: **/ std::unique_ptr MDNSService::registerService( - const std::string& serviceName, - const std::string& serviceType, - const std::string& serviceProto, - const std::string& serviceHost, - int servicePort, - const std::map txtData -) { - std::vector txtItems; - txtItems.reserve(txtData.size()); - for (auto& data : txtData) { - mdns_txt_item_t item; - item.key = data.first.c_str(); - item.value = data.second.c_str(); - txtItems.push_back(item); - } + const std::string& serviceName, const std::string& serviceType, + const std::string& serviceProto, const std::string& serviceHost, + int servicePort, const std::map txtData) { + std::vector txtItems; + txtItems.reserve(txtData.size()); + for (auto& data : txtData) { + mdns_txt_item_t item; + item.key = data.first.c_str(); + item.value = data.second.c_str(); + txtItems.push_back(item); + } - mdns_service_add( - serviceName.c_str(), /* instance_name */ - serviceType.c_str(), /* service_type */ - serviceProto.c_str(), /* proto */ - servicePort, /* port */ - txtItems.data(), /* txt */ - txtItems.size() /* num_items */ - ); + mdns_service_add(serviceName.c_str(), /* instance_name */ + serviceType.c_str(), /* service_type */ + serviceProto.c_str(), /* proto */ + servicePort, /* port */ + txtItems.data(), /* txt */ + txtItems.size() /* num_items */ + ); - return std::make_unique(serviceType, serviceProto); + return std::make_unique(serviceType, serviceProto); } diff --git a/components/spotify/cspot/bell/main/platform/esp/WrappedSemaphore.cpp b/components/spotify/cspot/bell/main/platform/esp/WrappedSemaphore.cpp index 01d7e4c6..af988b8f 100644 --- a/components/spotify/cspot/bell/main/platform/esp/WrappedSemaphore.cpp +++ b/components/spotify/cspot/bell/main/platform/esp/WrappedSemaphore.cpp @@ -6,36 +6,32 @@ using namespace bell; -WrappedSemaphore::WrappedSemaphore(int count) -{ - semaphoreHandle = xSemaphoreCreateCounting(count, 0); +WrappedSemaphore::WrappedSemaphore(int count) { + semaphoreHandle = xSemaphoreCreateCounting(count, 0); } -WrappedSemaphore::~WrappedSemaphore() -{ - vSemaphoreDelete(semaphoreHandle); +WrappedSemaphore::~WrappedSemaphore() { + vSemaphoreDelete(semaphoreHandle); } -int WrappedSemaphore::wait() -{ - if (xSemaphoreTake(semaphoreHandle, portMAX_DELAY) == pdTRUE) { - return 0; - } +int WrappedSemaphore::wait() { + if (xSemaphoreTake(semaphoreHandle, portMAX_DELAY) == pdTRUE) { + return 0; + } - return 1; + return 1; } -int WrappedSemaphore::twait(long milliseconds) -{ - if (xSemaphoreTake(semaphoreHandle, milliseconds / portTICK_PERIOD_MS) == pdTRUE) { - return 0; - } +int WrappedSemaphore::twait(long milliseconds) { + if (xSemaphoreTake(semaphoreHandle, milliseconds / portTICK_PERIOD_MS) == + pdTRUE) { + return 0; + } - return 1; + return 1; } -void WrappedSemaphore::give() -{ +void WrappedSemaphore::give() { - xSemaphoreGive(semaphoreHandle); + xSemaphoreGive(semaphoreHandle); } diff --git a/components/spotify/cspot/bell/main/platform/linux/MDNSService.cpp b/components/spotify/cspot/bell/main/platform/linux/MDNSService.cpp index 0109890b..0a9f36f2 100644 --- a/components/spotify/cspot/bell/main/platform/linux/MDNSService.cpp +++ b/components/spotify/cspot/bell/main/platform/linux/MDNSService.cpp @@ -1,9 +1,10 @@ -#include -#include #include +#include #include #include -#include +#include +#include +#include #if __has_include("avahi-client/client.h") #include @@ -14,40 +15,42 @@ #define BELL_DISABLE_AVAHI #endif -#include "mdnssvc.h" #include "BellLogger.h" #include "MDNSService.h" +#include "mdnssvc.h" using namespace bell; #ifndef BELL_DISABLE_AVAHI -static void groupHandler(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) { } +static void groupHandler(AvahiEntryGroup* g, AvahiEntryGroupState state, + AVAHI_GCC_UNUSED void* userdata) {} #endif class implMDNSService : public MDNSService { -private: + private: #ifndef BELL_DISABLE_AVAHI - AvahiEntryGroup *avahiGroup; + AvahiEntryGroup* avahiGroup; #endif - struct mdns_service* service; + struct mdns_service* service; -public: + public: #ifndef BELL_DISABLE_AVAHI - static AvahiClient *avahiClient; - static AvahiSimplePoll *avahiPoll; + static AvahiClient* avahiClient; + static AvahiSimplePoll* avahiPoll; #endif - static struct mdnsd* mdnsServer; - static in_addr_t host; + static struct mdnsd* mdnsServer; + static in_addr_t host; - implMDNSService(struct mdns_service* service) : service(service) { }; -#ifndef BELL_DISABLE_AVAHI - implMDNSService(AvahiEntryGroup *avahiGroup) : avahiGroup(avahiGroup) { }; -#endif - void unregisterService(); + implMDNSService(struct mdns_service* service) : service(service){}; +#ifndef BELL_DISABLE_AVAHI + implMDNSService(AvahiEntryGroup* avahiGroup) : avahiGroup(avahiGroup){}; +#endif + void unregisterService(); }; struct mdnsd* implMDNSService::mdnsServer = NULL; in_addr_t implMDNSService::host = INADDR_ANY; +static std::mutex registerMutex; #ifndef BELL_DISABLE_AVAHI AvahiClient* implMDNSService::avahiClient = NULL; AvahiSimplePoll* implMDNSService::avahiPoll = NULL; @@ -60,130 +63,135 @@ AvahiSimplePoll* implMDNSService::avahiPoll = NULL; void implMDNSService::unregisterService() { #ifndef BELL_DISABLE_AVAHI - if (avahiGroup) { - avahi_entry_group_free(avahiGroup); - } else + if (avahiGroup) { + avahi_entry_group_free(avahiGroup); + } else #endif - { - mdns_service_remove(implMDNSService::mdnsServer, service); - } + { + mdns_service_remove(implMDNSService::mdnsServer, service); + } } std::unique_ptr MDNSService::registerService( - const std::string& serviceName, - const std::string& serviceType, - const std::string& serviceProto, - const std::string& serviceHost, - int servicePort, - const std::map txtData -) { + const std::string& serviceName, const std::string& serviceType, + const std::string& serviceProto, const std::string& serviceHost, + int servicePort, const std::map txtData) { + std::lock_guard lock(registerMutex); #ifndef BELL_DISABLE_AVAHI - // try avahi first if available - if (!implMDNSService::avahiPoll) { - implMDNSService::avahiPoll = avahi_simple_poll_new(); + // try avahi first if available + if (!implMDNSService::avahiPoll) { + implMDNSService::avahiPoll = avahi_simple_poll_new(); + } + + if (implMDNSService::avahiPoll && !implMDNSService::avahiClient) { + implMDNSService::avahiClient = + avahi_client_new(avahi_simple_poll_get(implMDNSService::avahiPoll), + AvahiClientFlags(0), NULL, NULL, NULL); + } + AvahiEntryGroup* avahiGroup = NULL; + + if (implMDNSService::avahiClient && + (avahiGroup = avahi_entry_group_new(implMDNSService::avahiClient, + groupHandler, NULL)) == NULL) { + BELL_LOG(error, "MDNS", "cannot create service %s", serviceName.c_str()); + } + + if (avahiGroup != NULL) { + AvahiStringList* avahiTxt = NULL; + + for (auto& [key, value] : txtData) { + avahiTxt = + avahi_string_list_add_pair(avahiTxt, key.c_str(), value.c_str()); } - if (implMDNSService::avahiPoll && !implMDNSService::avahiClient) { - implMDNSService::avahiClient = avahi_client_new(avahi_simple_poll_get(implMDNSService::avahiPoll), - AvahiClientFlags(0), NULL, NULL, NULL); + std::string type(serviceType + "." + serviceProto); + int ret = avahi_entry_group_add_service_strlst( + avahiGroup, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, + serviceName.c_str(), type.c_str(), NULL, NULL, servicePort, avahiTxt); + avahi_string_list_free(avahiTxt); + + if (ret >= 0) { + ret = avahi_entry_group_commit(avahiGroup); } - - AvahiEntryGroup *avahiGroup; - if (implMDNSService::avahiClient && - (avahiGroup = avahi_entry_group_new(implMDNSService::avahiClient, groupHandler, NULL)) == NULL) { - BELL_LOG(error, "MDNS", "cannot create service %s", serviceName.c_str()); - } - - if (avahiGroup) { - AvahiStringList* avahiTxt = NULL; - - for (auto& [key, value] : txtData) { - avahiTxt = avahi_string_list_add_pair(avahiTxt, key.c_str(), value.c_str()); - } - - std::string type(serviceType + "." + serviceProto); - int ret = avahi_entry_group_add_service_strlst(avahiGroup, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags) 0, - serviceName.c_str(), type.c_str(), NULL, NULL, servicePort, avahiTxt); - avahi_string_list_free(avahiTxt); - - if (ret >= 0) { - ret = avahi_entry_group_commit(avahiGroup); - } - - if (ret < 0) { - BELL_LOG(error, "MDNS", "cannot run service %s", serviceName.c_str()); - avahi_entry_group_free(avahiGroup); - } else { - BELL_LOG(info, "MDNS", "using avahi for %s", serviceName.c_str()); - return std::make_unique(avahiGroup); - } + if (ret < 0) { + BELL_LOG(error, "MDNS", "cannot run service %s", serviceName.c_str()); + avahi_entry_group_free(avahiGroup); + } else { + BELL_LOG(info, "MDNS", "using avahi for %s", serviceName.c_str()); + return std::make_unique(avahiGroup); } + } #endif - // avahi failed, use build-in server - struct ifaddrs* ifaddr; + // avahi failed, use build-in server + struct ifaddrs* ifaddr; - // get the host address first - if (serviceHost.size()) { - struct hostent *h = gethostbyname(serviceHost.c_str()); - if (h) { - memcpy(&implMDNSService::host, h->h_addr_list[0], 4); - } + // get the host address first + if (serviceHost.size()) { + struct hostent* h = gethostbyname(serviceHost.c_str()); + if (h) { + memcpy(&implMDNSService::host, h->h_addr_list[0], 4); } + } - // try go guess ifaddr if we have nothing as listening to INADDR_ANY usually does not work - if (implMDNSService::host == INADDR_ANY && getifaddrs(&ifaddr) != -1) { - for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET || - !(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_MULTICAST) || - (ifa->ifa_flags & IFF_LOOPBACK)) continue; + // try go guess ifaddr if we have nothing as listening to INADDR_ANY usually does not work + if (implMDNSService::host == INADDR_ANY && getifaddrs(&ifaddr) != -1) { + for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET || + !(ifa->ifa_flags & IFF_UP) || !(ifa->ifa_flags & IFF_MULTICAST) || + (ifa->ifa_flags & IFF_LOOPBACK)) + continue; - implMDNSService::host = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr; - break; - } - freeifaddrs(ifaddr); - } - - if (!implMDNSService::mdnsServer) { - char hostname[256]; - struct in_addr addr; - - // it's the same, but who knows.. - addr.s_addr = implMDNSService::host; - gethostname(hostname, sizeof(hostname)); - - implMDNSService::mdnsServer = mdnsd_start(addr, false); - - if (implMDNSService::mdnsServer) { - mdnsd_set_hostname(implMDNSService::mdnsServer, hostname, addr); - } + implMDNSService::host = + ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr; + break; } + freeifaddrs(ifaddr); + } + + if (!implMDNSService::mdnsServer) { + char hostname[256]; + struct in_addr addr; + + // it's the same, but who knows.. + addr.s_addr = implMDNSService::host; + gethostname(hostname, sizeof(hostname)); + + implMDNSService::mdnsServer = mdnsd_start(addr, false); if (implMDNSService::mdnsServer) { - std::vector txt; - std::vector> txtStr; + mdnsd_set_hostname(implMDNSService::mdnsServer, hostname, addr); + } + } - for (auto& [key, value] : txtData) { - auto str = make_unique(key + "=" + value); - txtStr.push_back(std::move(str)); - txt.push_back(txtStr.back()->c_str()); - } + if (implMDNSService::mdnsServer) { + std::vector txt; + std::vector> txtStr; - txt.push_back(NULL); - std::string type(serviceType + "." + serviceProto + ".local"); - - BELL_LOG(info, "MDNS", "using built-in mDNS for %s", serviceName.c_str()); - struct mdns_service* mdnsService = mdnsd_register_svc(implMDNSService::mdnsServer, serviceName.c_str(), - type.c_str(), servicePort, NULL, txt.data()); - if (mdnsService) { - auto service = mdnsd_register_svc(implMDNSService::mdnsServer, serviceName.c_str(), - type.c_str(), servicePort, NULL, txt.data()); - - return std::make_unique(service); - } + for (auto& [key, value] : txtData) { + auto str = make_unique(key + "=" + value); + txtStr.push_back(std::move(str)); + txt.push_back(txtStr.back()->c_str()); } - BELL_LOG(error, "MDNS", "cannot start any mDNS listener for %s", serviceName.c_str()); - return NULL; + txt.push_back(NULL); + std::string type(serviceType + "." + serviceProto + ".local"); + + BELL_LOG(info, "MDNS", "using built-in mDNS for %s", serviceName.c_str()); + struct mdns_service* mdnsService = + mdnsd_register_svc(implMDNSService::mdnsServer, serviceName.c_str(), + type.c_str(), servicePort, NULL, txt.data()); + if (mdnsService) { + auto service = + mdnsd_register_svc(implMDNSService::mdnsServer, serviceName.c_str(), + type.c_str(), servicePort, NULL, txt.data()); + + return std::make_unique(service); + } + } + + BELL_LOG(error, "MDNS", "cannot start any mDNS listener for %s", + serviceName.c_str()); + return NULL; } diff --git a/components/spotify/cspot/bell/main/platform/linux/WrappedSemaphore.cpp b/components/spotify/cspot/bell/main/platform/linux/WrappedSemaphore.cpp index 131d0b9e..ca44436d 100644 --- a/components/spotify/cspot/bell/main/platform/linux/WrappedSemaphore.cpp +++ b/components/spotify/cspot/bell/main/platform/linux/WrappedSemaphore.cpp @@ -1,33 +1,33 @@ #include "WrappedSemaphore.h" +#include using namespace bell; -WrappedSemaphore::WrappedSemaphore(int count) -{ - sem_init(&this->semaphoreHandle, 0, 0); // eek pointer +WrappedSemaphore::WrappedSemaphore(int count) { + sem_init(&this->semaphoreHandle, 0, 0); // eek pointer } -WrappedSemaphore::~WrappedSemaphore() -{ - sem_destroy(&this->semaphoreHandle); +WrappedSemaphore::~WrappedSemaphore() { + sem_destroy(&this->semaphoreHandle); } -int WrappedSemaphore::wait() -{ - sem_wait(&this->semaphoreHandle); - return 0; +int WrappedSemaphore::wait() { + sem_wait(&this->semaphoreHandle); + return 0; } -int WrappedSemaphore::twait(long milliseconds) -{ - // wait on semaphore with timeout - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_nsec += (milliseconds % 1000) * 1000000; - return sem_timedwait(&this->semaphoreHandle, &ts); +int WrappedSemaphore::twait(long milliseconds) { + // wait on semaphore with timeout + struct timespec ts; + struct timeval tv; + + gettimeofday(&tv, 0); + + ts.tv_sec = tv.tv_sec + milliseconds / 1000; + ts.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000; + return sem_timedwait(&this->semaphoreHandle, &ts); } -void WrappedSemaphore::give() -{ - sem_post(&this->semaphoreHandle); +void WrappedSemaphore::give() { + sem_post(&this->semaphoreHandle); } diff --git a/components/spotify/cspot/bell/main/platform/win32/MDNSService.cpp b/components/spotify/cspot/bell/main/platform/win32/MDNSService.cpp index fb91061a..7ee64a17 100644 --- a/components/spotify/cspot/bell/main/platform/win32/MDNSService.cpp +++ b/components/spotify/cspot/bell/main/platform/win32/MDNSService.cpp @@ -1,8 +1,8 @@ -#include #include +#include -#include "MDNSService.h" #include "BellLogger.h" +#include "MDNSService.h" #ifdef _WIN32 #include @@ -12,19 +12,20 @@ #else #include #include "mdns.h" -#include #endif using namespace bell; class implMDNSService : public MDNSService { -private: - struct mdns_service* service; - void unregisterService(void) { mdns_service_remove(implMDNSService::mdnsServer, service); }; - -public: - static struct mdnsd* mdnsServer; - implMDNSService(struct mdns_service* service) : service(service) { }; + private: + struct mdns_service* service; + void unregisterService(void) { + mdns_service_remove(implMDNSService::mdnsServer, service); + }; + + public: + static struct mdnsd* mdnsServer; + implMDNSService(struct mdns_service* service) : service(service){}; }; /** @@ -32,58 +33,66 @@ public: **/ struct mdnsd* implMDNSService::mdnsServer = NULL; +static std::mutex registerMutex; std::unique_ptr MDNSService::registerService( - const std::string& serviceName, - const std::string& serviceType, - const std::string& serviceProto, - const std::string& serviceHost, - int servicePort, - const std::map txtData -) { - if (!implMDNSService::mdnsServer) { - char hostname[128]; - gethostname(hostname, sizeof(hostname)); + const std::string& serviceName, const std::string& serviceType, + const std::string& serviceProto, const std::string& serviceHost, + int servicePort, const std::map txtData) { + std::lock_guard lock(registerMutex); + if (!implMDNSService::mdnsServer) { + char hostname[128]; + gethostname(hostname, sizeof(hostname)); - struct sockaddr_in* host = NULL; - ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 64; - IP_ADAPTER_ADDRESSES* adapters = (IP_ADAPTER_ADDRESSES*)malloc(size); - int ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST, 0, adapters, &size); + struct sockaddr_in* host = NULL; + ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 64; + IP_ADAPTER_ADDRESSES* adapters = (IP_ADAPTER_ADDRESSES*)malloc(size); + int ret = GetAdaptersAddresses(AF_UNSPEC, + GAA_FLAG_INCLUDE_GATEWAYS | + GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_ANYCAST, + 0, adapters, &size); - for (PIP_ADAPTER_ADDRESSES adapter = adapters; adapter && !host; adapter = adapter->Next) { - if (adapter->TunnelType == TUNNEL_TYPE_TEREDO) continue; - if (adapter->OperStatus != IfOperStatusUp) continue; + for (PIP_ADAPTER_ADDRESSES adapter = adapters; adapter && !host; + adapter = adapter->Next) { + if (adapter->TunnelType == TUNNEL_TYPE_TEREDO) + continue; + if (adapter->OperStatus != IfOperStatusUp) + continue; - for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; unicast; - unicast = unicast->Next) { - if (adapter->FirstGatewayAddress && unicast->Address.lpSockaddr->sa_family == AF_INET) { - host = (struct sockaddr_in*)unicast->Address.lpSockaddr; - BELL_LOG(info, "mdns", "mDNS on interface %s", inet_ntoa(host->sin_addr)); - implMDNSService::mdnsServer = mdnsd_start(host->sin_addr, false); - break; - } - } + for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; + unicast; unicast = unicast->Next) { + if (adapter->FirstGatewayAddress && + unicast->Address.lpSockaddr->sa_family == AF_INET) { + host = (struct sockaddr_in*)unicast->Address.lpSockaddr; + BELL_LOG(info, "mdns", "mDNS on interface %s", + inet_ntoa(host->sin_addr)); + implMDNSService::mdnsServer = mdnsd_start(host->sin_addr, false); + break; } - - assert(implMDNSService::mdnsServer); - mdnsd_set_hostname(implMDNSService::mdnsServer, hostname, host->sin_addr); - free(adapters); + } } - std::vector txt; - std::vector> txtStr; + assert(implMDNSService::mdnsServer); + mdnsd_set_hostname(implMDNSService::mdnsServer, hostname, host->sin_addr); + free(adapters); + } - for (auto& [key, value] : txtData) { - auto str = make_unique(key + "=" + value); - txtStr.push_back(std::move(str)); - txt.push_back(txtStr.back()->c_str()); - } - txt.push_back(NULL); + std::vector txt; + std::vector> txtStr; - std::string type(serviceType + "." + serviceProto + ".local"); + for (auto& [key, value] : txtData) { + auto str = make_unique(key + "=" + value); + txtStr.push_back(std::move(str)); + txt.push_back(txtStr.back()->c_str()); + } + txt.push_back(NULL); - auto service = mdnsd_register_svc(implMDNSService::mdnsServer, serviceName.c_str(), - type.c_str(), servicePort, NULL, txt.data()); + std::string type(serviceType + "." + serviceProto + ".local"); - return std::make_unique(service); + auto service = + mdnsd_register_svc(implMDNSService::mdnsServer, serviceName.c_str(), + type.c_str(), servicePort, NULL, txt.data()); + + return std::make_unique(service); } diff --git a/components/spotify/cspot/bell/main/platform/win32/WrappedSemaphore.cpp b/components/spotify/cspot/bell/main/platform/win32/WrappedSemaphore.cpp index 4ed8c491..20c33825 100644 --- a/components/spotify/cspot/bell/main/platform/win32/WrappedSemaphore.cpp +++ b/components/spotify/cspot/bell/main/platform/win32/WrappedSemaphore.cpp @@ -2,28 +2,24 @@ using namespace bell; -WrappedSemaphore::WrappedSemaphore(int count) -{ - this->semaphoreHandle = CreateSemaphore(NULL, 0, count, NULL); +WrappedSemaphore::WrappedSemaphore(int count) { + this->semaphoreHandle = CreateSemaphore(NULL, 0, count, NULL); } -WrappedSemaphore::~WrappedSemaphore() -{ - CloseHandle(this->semaphoreHandle); +WrappedSemaphore::~WrappedSemaphore() { + CloseHandle(this->semaphoreHandle); } -int WrappedSemaphore::wait() -{ - WaitForSingleObject(this->semaphoreHandle, INFINITE); - return 0; +int WrappedSemaphore::wait() { + WaitForSingleObject(this->semaphoreHandle, INFINITE); + return 0; } -int WrappedSemaphore::twait(long milliseconds) -{ - return WaitForSingleObject(this->semaphoreHandle, milliseconds) != WAIT_OBJECT_0; +int WrappedSemaphore::twait(long milliseconds) { + return WaitForSingleObject(this->semaphoreHandle, milliseconds) != + WAIT_OBJECT_0; } -void WrappedSemaphore::give() -{ - ReleaseSemaphore(this->semaphoreHandle, 1, NULL); +void WrappedSemaphore::give() { + ReleaseSemaphore(this->semaphoreHandle, 1, NULL); } diff --git a/components/spotify/cspot/bell/main/platform/win32/win32shim.h b/components/spotify/cspot/bell/main/platform/win32/win32shim.h index 57fbedfa..f06bebf3 100644 --- a/components/spotify/cspot/bell/main/platform/win32/win32shim.h +++ b/components/spotify/cspot/bell/main/platform/win32/win32shim.h @@ -7,8 +7,12 @@ #define strcasecmp stricmp #define strncasecmp _strnicmp -#define bzero(p,n) memset(p,0,n) -#define usleep(x) Sleep((x)/1000) +#define bzero(p, n) memset(p, 0, n) +#define usleep(x) Sleep((x) / 1000) -inline size_t read(int sock, char* buf, size_t n) { return recv(sock, buf, n, 0); } -inline int write(int sock, const char* buf, size_t n) { return send(sock, buf, n, 0); } +inline size_t read(int sock, char* buf, size_t n) { + return recv(sock, buf, n, 0); +} +inline int write(int sock, const char* buf, size_t n) { + return send(sock, buf, n, 0); +} diff --git a/components/spotify/cspot/bell/main/utilities/BellLogger.cpp b/components/spotify/cspot/bell/main/utilities/BellLogger.cpp index 975b2975..46ec6d92 100644 --- a/components/spotify/cspot/bell/main/utilities/BellLogger.cpp +++ b/components/spotify/cspot/bell/main/utilities/BellLogger.cpp @@ -3,9 +3,13 @@ bell::AbstractLogger* bell::bellGlobalLogger; void bell::setDefaultLogger() { - bell::bellGlobalLogger = new bell::BellLogger(); + bell::bellGlobalLogger = new bell::BellLogger(); } void bell::enableSubmoduleLogging() { - bell::bellGlobalLogger->enableSubmodule = true; -} \ No newline at end of file + bell::bellGlobalLogger->enableSubmodule = true; +} + +void bell::enableTimestampLogging() { + bell::bellGlobalLogger->enableTimestamp = true; +} diff --git a/components/spotify/cspot/bell/main/utilities/BellUtils.cpp b/components/spotify/cspot/bell/main/utilities/BellUtils.cpp index f77a1368..902252f3 100644 --- a/components/spotify/cspot/bell/main/utilities/BellUtils.cpp +++ b/components/spotify/cspot/bell/main/utilities/BellUtils.cpp @@ -1,5 +1,11 @@ #include "BellUtils.h" +#include // for free +#include // for mt19937, uniform_int_distribution, random_device +#ifdef ESP_PLATFORM +#include "esp_system.h" +#endif + std::string bell::generateRandomUUID() { static std::random_device dev; static std::mt19937 rng(dev()); diff --git a/components/spotify/cspot/bell/main/utilities/Crypto.cpp b/components/spotify/cspot/bell/main/utilities/Crypto.cpp index ab4883b0..28c2d31d 100644 --- a/components/spotify/cspot/bell/main/utilities/Crypto.cpp +++ b/components/spotify/cspot/bell/main/utilities/Crypto.cpp @@ -1,5 +1,17 @@ #include "Crypto.h" +#include // for mbedtls_base64_encode, mbedtls_base64_... +#include // for mbedtls_mpi_free, mbedtls_mpi_init +#include // for mbedtls_ctr_drbg_free, mbedtls_ctr_drb... +#include // for mbedtls_entropy_free, mbedtls_entropy_... +#include // for mbedtls_pkcs5_pbkdf2_hmac +#include // for uint8_t +#include // for runtime_error + +extern "C" { +#include "aes.h" // for AES_ECB_decrypt, AES_init_ctx, AES_ctx +} + CryptoMbedTLS::CryptoMbedTLS() {} CryptoMbedTLS::~CryptoMbedTLS() { diff --git a/components/spotify/cspot/bell/main/utilities/NanoPBHelper.cpp b/components/spotify/cspot/bell/main/utilities/NanoPBHelper.cpp index 9a4170c7..4bd626d5 100644 --- a/components/spotify/cspot/bell/main/utilities/NanoPBHelper.cpp +++ b/components/spotify/cspot/bell/main/utilities/NanoPBHelper.cpp @@ -1,78 +1,82 @@ #include "NanoPBHelper.h" -static bool vectorWrite(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) -{ - size_t i; - auto *dest = reinterpret_cast *>(stream->state); +#include // for malloc +#include // for strcpy, memcpy, strlen +#include // for copy +#include // for uint8_t - dest->insert(dest->end(), buf, buf + count); +#include "pb_encode.h" // for pb_ostream_s, pb_encode, pb_get_encoded_size - return true; +static bool vectorWrite(pb_ostream_t* stream, const pb_byte_t* buf, + size_t count) { + size_t i; + auto* dest = reinterpret_cast*>(stream->state); + + dest->insert(dest->end(), buf, buf + count); + + return true; } -pb_ostream_t pb_ostream_from_vector(std::vector &vec) -{ - pb_ostream_t stream; +pb_ostream_t pb_ostream_from_vector(std::vector& vec) { + pb_ostream_t stream; - stream.callback = &vectorWrite; - stream.state = &vec; - stream.max_size = 100000; - stream.bytes_written = 0; + stream.callback = &vectorWrite; + stream.state = &vec; + stream.max_size = 100000; + stream.bytes_written = 0; - return stream; + return stream; } -std::vector pbEncode(const pb_msgdesc_t *fields, const void *src_struct) -{ - std::vector vecData(0); - pb_ostream_t stream = pb_ostream_from_vector(vecData); - pb_encode(&stream, fields, src_struct); +std::vector pbEncode(const pb_msgdesc_t* fields, + const void* src_struct) { + std::vector vecData(0); + pb_ostream_t stream = pb_ostream_from_vector(vecData); + pb_encode(&stream, fields, src_struct); - return vecData; + return vecData; } -void packString(char *&dst, std::string stringToPack) -{ - dst = (char *)malloc((strlen(stringToPack.c_str()) + 1) * sizeof(char)); - strcpy(dst, stringToPack.c_str()); +void packString(char*& dst, std::string stringToPack) { + dst = (char*)malloc((strlen(stringToPack.c_str()) + 1) * sizeof(char)); + strcpy(dst, stringToPack.c_str()); } -pb_bytes_array_t* vectorToPbArray(const std::vector& vectorToPack) -{ - auto size = static_cast(vectorToPack.size()); - auto result = static_cast( - malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size))); - result->size = size; - memcpy(result->bytes, vectorToPack.data(), size); - return result; +pb_bytes_array_t* vectorToPbArray(const std::vector& vectorToPack) { + auto size = static_cast(vectorToPack.size()); + auto result = + static_cast(malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(size))); + result->size = size; + memcpy(result->bytes, vectorToPack.data(), size); + return result; } -void pbPutString(const std::string &stringToPack, char* dst) { - stringToPack.copy(dst, stringToPack.size()); - dst[stringToPack.size()] = '\0'; +void pbPutString(const std::string& stringToPack, char* dst) { + stringToPack.copy(dst, stringToPack.size()); + dst[stringToPack.size()] = '\0'; } -void pbPutCharArray(const char * stringToPack, char* dst) { - // copy stringToPack into dst - strcpy(dst, stringToPack); - //dst[sizeof(stringToPack)-1] = '\0'; +void pbPutCharArray(const char* stringToPack, char* dst) { + // copy stringToPack into dst + strcpy(dst, stringToPack); + //dst[sizeof(stringToPack)-1] = '\0'; } -void pbPutBytes(const std::vector &data, pb_bytes_array_t &dst) { - dst.size = data.size(); - std::copy(data.begin(), data.end(), dst.bytes); +void pbPutBytes(const std::vector& data, pb_bytes_array_t& dst) { + dst.size = data.size(); + std::copy(data.begin(), data.end(), dst.bytes); } std::vector pbArrayToVector(pb_bytes_array_t* pbArray) { - return std::vector(pbArray->bytes, pbArray->bytes + pbArray->size); + return std::vector(pbArray->bytes, pbArray->bytes + pbArray->size); } -const char *pb_encode_to_string(const pb_msgdesc_t *fields, const void *data) { - size_t len; - pb_get_encoded_size(&len, fields, data); - auto *buf = static_cast(malloc(len + 1)); - auto ostream = pb_ostream_from_buffer(buf, len); - pb_encode(&ostream, fields, data); - buf[len] = '\0'; - return reinterpret_cast(buf); +const char* pb_encode_to_string(const pb_msgdesc_t* fields, const void* data) { + size_t len; + pb_get_encoded_size(&len, fields, data); + auto* buf = static_cast(malloc(len + 1)); + auto ostream = pb_ostream_from_buffer(buf, len); + pb_encode(&ostream, fields, data); + buf[len] = '\0'; + return reinterpret_cast(buf); } \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/utilities/aes.c b/components/spotify/cspot/bell/main/utilities/aes.c index 2bd115e2..2ed66c69 100644 --- a/components/spotify/cspot/bell/main/utilities/aes.c +++ b/components/spotify/cspot/bell/main/utilities/aes.c @@ -31,12 +31,13 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) */ - +#include // for uint8_t /*****************************************************************************/ /* Includes: */ /*****************************************************************************/ -#include // CBC mode, for memset -#include "aes.h" +#include // for memcpy, size_t + +#include "aes.h" // for AES_ctx, AES_BLOCKLEN, CBC, ECB, CTR, AES192 /*****************************************************************************/ /* Defines: */ @@ -45,80 +46,87 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) #define Nb 4 #if defined(AES256) && (AES256 == 1) - #define Nk 8 - #define Nr 14 +#define Nk 8 +#define Nr 14 #elif defined(AES192) && (AES192 == 1) - #define Nk 6 - #define Nr 12 +#define Nk 6 +#define Nr 12 #else - #define Nk 4 // The number of 32 bit words in a key. - #define Nr 10 // The number of rounds in AES Cipher. +#define Nk 4 // The number of 32 bit words in a key. +#define Nr 10 // The number of rounds in AES Cipher. #endif -// jcallan@github points out that declaring Multiply as a function +// jcallan@github points out that declaring Multiply as a function // reduces code size considerably with the Keil ARM compiler. // See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 #ifndef MULTIPLY_AS_A_FUNCTION - #define MULTIPLY_AS_A_FUNCTION 0 +#define MULTIPLY_AS_A_FUNCTION 0 #endif - - - /*****************************************************************************/ /* Private variables: */ /*****************************************************************************/ // state - array holding the intermediate results during decryption. typedef uint8_t state_t[4][4]; - - // The lookup-tables are marked const so they can be placed in read-only storage instead of RAM -// The numbers below can be computed dynamically trading ROM for RAM - +// The numbers below can be computed dynamically trading ROM for RAM - // This can be useful in (embedded) bootloader applications, where ROM is often limited. static const uint8_t sbox[256] = { - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, + 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, + 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, + 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, + 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, + 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, + 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, + 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, + 0xb0, 0x54, 0xbb, 0x16}; #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) static const uint8_t rsbox[256] = { - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, + 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, + 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, + 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, + 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, + 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, + 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, + 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, + 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, + 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0c, 0x7d}; #endif -// The round constant word array, Rcon[i], contains the values given by +// The round constant word array, Rcon[i], contains the values given by // x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) -static const uint8_t Rcon[11] = { - 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; +static const uint8_t Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x1b, 0x36}; /* * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), @@ -130,7 +138,6 @@ static const uint8_t Rcon[11] = { * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." */ - /*****************************************************************************/ /* Private functions: */ /*****************************************************************************/ @@ -142,15 +149,13 @@ static uint8_t getSBoxValue(uint8_t num) */ #define getSBoxValue(num) (sbox[(num)]) -// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. -static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) -{ +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) { unsigned i, j, k; - uint8_t tempa[4]; // Used for the column/row operations - + uint8_t tempa[4]; // Used for the column/row operations + // The first round key is the key itself. - for (i = 0; i < Nk; ++i) - { + for (i = 0; i < Nk; ++i) { RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; @@ -158,19 +163,16 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) } // All other round keys are found from the previous round keys. - for (i = Nk; i < Nb * (Nr + 1); ++i) - { + for (i = Nk; i < Nb * (Nr + 1); ++i) { { k = (i - 1) * 4; - tempa[0]=RoundKey[k + 0]; - tempa[1]=RoundKey[k + 1]; - tempa[2]=RoundKey[k + 2]; - tempa[3]=RoundKey[k + 3]; - + tempa[0] = RoundKey[k + 0]; + tempa[1] = RoundKey[k + 1]; + tempa[2] = RoundKey[k + 2]; + tempa[3] = RoundKey[k + 3]; } - if (i % Nk == 0) - { + if (i % Nk == 0) { // This function shifts the 4 bytes in a word to the left once. // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] @@ -183,7 +185,7 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) tempa[3] = u8tmp; } - // SubWord() is a function that takes a four-byte input word and + // SubWord() is a function that takes a four-byte input word and // applies the S-box to each of the four bytes to produce an output word. // Function Subword() @@ -194,11 +196,10 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) tempa[3] = getSBoxValue(tempa[3]); } - tempa[0] = tempa[0] ^ Rcon[i/Nk]; + tempa[0] = tempa[0] ^ Rcon[i / Nk]; } #if defined(AES256) && (AES256 == 1) - if (i % Nk == 4) - { + if (i % Nk == 4) { // Function Subword() { tempa[0] = getSBoxValue(tempa[0]); @@ -208,7 +209,8 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) } } #endif - j = i * 4; k=(i - Nk) * 4; + j = i * 4; + k = (i - Nk) * 4; RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; @@ -216,31 +218,27 @@ static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) } } -void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) -{ +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) { KeyExpansion(ctx->RoundKey, key); } #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) -void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) -{ +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, + const uint8_t* iv) { KeyExpansion(ctx->RoundKey, key); - memcpy (ctx->Iv, iv, AES_BLOCKLEN); + memcpy(ctx->Iv, iv, AES_BLOCKLEN); } -void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) -{ - memcpy (ctx->Iv, iv, AES_BLOCKLEN); +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) { + memcpy(ctx->Iv, iv, AES_BLOCKLEN); } #endif // This function adds the round key to state. // The round key is added to the state by an XOR function. -static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) -{ - uint8_t i,j; - for (i = 0; i < 4; ++i) - { - for (j = 0; j < 4; ++j) - { +static void AddRoundKey(uint8_t round, state_t* state, + const uint8_t* RoundKey) { + uint8_t i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; } } @@ -248,13 +246,10 @@ static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) // The SubBytes Function Substitutes the values in the // state matrix with values in an S-box. -static void SubBytes(state_t* state) -{ +static void SubBytes(state_t* state) { uint8_t i, j; - for (i = 0; i < 4; ++i) - { - for (j = 0; j < 4; ++j) - { + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { (*state)[j][i] = getSBoxValue((*state)[j][i]); } } @@ -263,52 +258,56 @@ static void SubBytes(state_t* state) // The ShiftRows() function shifts the rows in the state to the left. // Each row is shifted with different offset. // Offset = Row number. So the first row is not shifted. -static void ShiftRows(state_t* state) -{ +static void ShiftRows(state_t* state) { uint8_t temp; - // Rotate first row 1 columns to left - temp = (*state)[0][1]; + // Rotate first row 1 columns to left + temp = (*state)[0][1]; (*state)[0][1] = (*state)[1][1]; (*state)[1][1] = (*state)[2][1]; (*state)[2][1] = (*state)[3][1]; (*state)[3][1] = temp; - // Rotate second row 2 columns to left - temp = (*state)[0][2]; + // Rotate second row 2 columns to left + temp = (*state)[0][2]; (*state)[0][2] = (*state)[2][2]; (*state)[2][2] = temp; - temp = (*state)[1][2]; + temp = (*state)[1][2]; (*state)[1][2] = (*state)[3][2]; (*state)[3][2] = temp; // Rotate third row 3 columns to left - temp = (*state)[0][3]; + temp = (*state)[0][3]; (*state)[0][3] = (*state)[3][3]; (*state)[3][3] = (*state)[2][3]; (*state)[2][3] = (*state)[1][3]; (*state)[1][3] = temp; } -static uint8_t xtime(uint8_t x) -{ - return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); +static uint8_t xtime(uint8_t x) { + return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); } // MixColumns function mixes the columns of the state matrix -static void MixColumns(state_t* state) -{ +static void MixColumns(state_t* state) { uint8_t i; uint8_t Tmp, Tm, t; - for (i = 0; i < 4; ++i) - { - t = (*state)[i][0]; - Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; - Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; - Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; - Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; - Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; + for (i = 0; i < 4; ++i) { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3]; + Tm = (*state)[i][0] ^ (*state)[i][1]; + Tm = xtime(Tm); + (*state)[i][0] ^= Tm ^ Tmp; + Tm = (*state)[i][1] ^ (*state)[i][2]; + Tm = xtime(Tm); + (*state)[i][1] ^= Tm ^ Tmp; + Tm = (*state)[i][2] ^ (*state)[i][3]; + Tm = xtime(Tm); + (*state)[i][2] ^= Tm ^ Tmp; + Tm = (*state)[i][3] ^ t; + Tm = xtime(Tm); + (*state)[i][3] ^= Tm ^ Tmp; } } @@ -317,21 +316,20 @@ static void MixColumns(state_t* state) // The compiler seems to be able to vectorize the operation better this way. // See https://github.com/kokke/tiny-AES-c/pull/34 #if MULTIPLY_AS_A_FUNCTION -static uint8_t Multiply(uint8_t x, uint8_t y) -{ - return (((y & 1) * x) ^ - ((y>>1 & 1) * xtime(x)) ^ - ((y>>2 & 1) * xtime(xtime(x))) ^ - ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ - ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ - } +static uint8_t Multiply(uint8_t x, uint8_t y) { + return (((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ + ((y >> 2 & 1) * xtime(xtime(x))) ^ + ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y >> 4 & 1) * + xtime(xtime(xtime( + xtime(x)))))); /* this last call to xtime() can be omitted */ +} #else -#define Multiply(x, y) \ - ( ((y & 1) * x) ^ \ - ((y>>1 & 1) * xtime(x)) ^ \ - ((y>>2 & 1) * xtime(xtime(x))) ^ \ - ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ - ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ +#define Multiply(x, y) \ + (((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ \ + ((y >> 2 & 1) * xtime(xtime(x))) ^ \ + ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))) #endif @@ -347,51 +345,48 @@ static uint8_t getSBoxInvert(uint8_t num) // MixColumns function mixes the columns of the state matrix. // The method used to multiply may be difficult to understand for the inexperienced. // Please use the references to gain more information. -static void InvMixColumns(state_t* state) -{ +static void InvMixColumns(state_t* state) { int i; uint8_t a, b, c, d; - for (i = 0; i < 4; ++i) - { + for (i = 0; i < 4; ++i) { a = (*state)[i][0]; b = (*state)[i][1]; c = (*state)[i][2]; d = (*state)[i][3]; - (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); - (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); - (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); - (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ + Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ + Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ + Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ + Multiply(d, 0x0e); } } - // The SubBytes Function Substitutes the values in the // state matrix with values in an S-box. -static void InvSubBytes(state_t* state) -{ +static void InvSubBytes(state_t* state) { uint8_t i, j; - for (i = 0; i < 4; ++i) - { - for (j = 0; j < 4; ++j) - { + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { (*state)[j][i] = getSBoxInvert((*state)[j][i]); } } } -static void InvShiftRows(state_t* state) -{ +static void InvShiftRows(state_t* state) { uint8_t temp; - // Rotate first row 1 columns to right + // Rotate first row 1 columns to right temp = (*state)[3][1]; (*state)[3][1] = (*state)[2][1]; (*state)[2][1] = (*state)[1][1]; (*state)[1][1] = (*state)[0][1]; (*state)[0][1] = temp; - // Rotate second row 2 columns to right + // Rotate second row 2 columns to right temp = (*state)[0][2]; (*state)[0][2] = (*state)[2][2]; (*state)[2][2] = temp; @@ -407,11 +402,10 @@ static void InvShiftRows(state_t* state) (*state)[2][3] = (*state)[3][3]; (*state)[3][3] = temp; } -#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) // Cipher is the main function that encrypts the PlainText. -static void Cipher(state_t* state, const uint8_t* RoundKey) -{ +static void Cipher(state_t* state, const uint8_t* RoundKey) { uint8_t round = 0; // Add the First round key to the state before starting the rounds. @@ -421,8 +415,7 @@ static void Cipher(state_t* state, const uint8_t* RoundKey) // The first Nr-1 rounds are identical. // These Nr rounds are executed in the loop below. // Last one without MixColumns() - for (round = 1; ; ++round) - { + for (round = 1;; ++round) { SubBytes(state); ShiftRows(state); if (round == Nr) { @@ -436,8 +429,7 @@ static void Cipher(state_t* state, const uint8_t* RoundKey) } #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) -static void InvCipher(state_t* state, const uint8_t* RoundKey) -{ +static void InvCipher(state_t* state, const uint8_t* RoundKey) { uint8_t round = 0; // Add the First round key to the state before starting the rounds. @@ -447,8 +439,7 @@ static void InvCipher(state_t* state, const uint8_t* RoundKey) // The first Nr-1 rounds are identical. // These Nr rounds are executed in the loop below. // Last one without InvMixColumn() - for (round = (Nr - 1); ; --round) - { + for (round = (Nr - 1);; --round) { InvShiftRows(state); InvSubBytes(state); AddRoundKey(round, state, RoundKey); @@ -457,53 +448,41 @@ static void InvCipher(state_t* state, const uint8_t* RoundKey) } InvMixColumns(state); } - } -#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) /*****************************************************************************/ /* Public functions: */ /*****************************************************************************/ #if defined(ECB) && (ECB == 1) - -void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) -{ +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) { // The next function call encrypts the PlainText with the Key using AES algorithm. Cipher((state_t*)buf, ctx->RoundKey); } -void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) -{ +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) { // The next function call decrypts the PlainText with the Key using AES algorithm. InvCipher((state_t*)buf, ctx->RoundKey); } - -#endif // #if defined(ECB) && (ECB == 1) - - - - +#endif // #if defined(ECB) && (ECB == 1) #if defined(CBC) && (CBC == 1) - -static void XorWithIv(uint8_t* buf, const uint8_t* Iv) -{ +static void XorWithIv(uint8_t* buf, const uint8_t* Iv) { uint8_t i; - for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size + for (i = 0; i < AES_BLOCKLEN; + ++i) // The block in AES is always 128bit no matter the key size { buf[i] ^= Iv[i]; } } -void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length) -{ +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { size_t i; - uint8_t *Iv = ctx->Iv; - for (i = 0; i < length; i += AES_BLOCKLEN) - { + uint8_t* Iv = ctx->Iv; + for (i = 0; i < length; i += AES_BLOCKLEN) { XorWithIv(buf, Iv); Cipher((state_t*)buf, ctx->RoundKey); Iv = buf; @@ -513,53 +492,44 @@ void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, size_t length) memcpy(ctx->Iv, Iv, AES_BLOCKLEN); } -void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) -{ +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { size_t i; uint8_t storeNextIv[AES_BLOCKLEN]; - for (i = 0; i < length; i += AES_BLOCKLEN) - { + for (i = 0; i < length; i += AES_BLOCKLEN) { memcpy(storeNextIv, buf, AES_BLOCKLEN); InvCipher((state_t*)buf, ctx->RoundKey); XorWithIv(buf, ctx->Iv); memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); buf += AES_BLOCKLEN; } - } -#endif // #if defined(CBC) && (CBC == 1) - - +#endif // #if defined(CBC) && (CBC == 1) #if defined(CTR) && (CTR == 1) /* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ -void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) -{ +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { uint8_t buffer[AES_BLOCKLEN]; - + size_t i; int bi; - for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) - { + for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) { if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ { - + memcpy(buffer, ctx->Iv, AES_BLOCKLEN); - Cipher((state_t*)buffer,ctx->RoundKey); + Cipher((state_t*)buffer, ctx->RoundKey); /* Increment Iv and handle overflow */ - for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) - { - /* inc will overflow */ - if (ctx->Iv[bi] == 255) - { + for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) { + /* inc will overflow */ + if (ctx->Iv[bi] == 255) { ctx->Iv[bi] = 0; continue; - } + } ctx->Iv[bi] += 1; - break; + break; } bi = 0; } @@ -568,4 +538,4 @@ void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) } } -#endif // #if defined(CTR) && (CTR == 1) +#endif // #if defined(CTR) && (CTR == 1) diff --git a/components/spotify/cspot/bell/main/utilities/include/BellLogger.h b/components/spotify/cspot/bell/main/utilities/include/BellLogger.h index a71784b3..ba6694c3 100644 --- a/components/spotify/cspot/bell/main/utilities/include/BellLogger.h +++ b/components/spotify/cspot/bell/main/utilities/include/BellLogger.h @@ -1,120 +1,140 @@ #ifndef BELL_LOGGER_H #define BELL_LOGGER_H -#include -#include -#include -#include -#include +#include // for va_end, va_list, va_start +#include // for printf, vprintf +#include +#include +#include +#include // for string, basic_string -namespace bell -{ +namespace bell { - class AbstractLogger - { - public: - bool enableSubmodule = false; - virtual void debug(std::string filename, int line, std::string submodule, const char *format, ...) = 0; - virtual void error(std::string filename, int line, std::string submodule, const char *format, ...) = 0; - virtual void info(std::string filename, int line, std::string submodule, const char *format, ...) = 0; - }; +class AbstractLogger { + public: + bool enableSubmodule = false; + bool enableTimestamp = false; - extern bell::AbstractLogger* bellGlobalLogger; - class BellLogger : public bell::AbstractLogger - { - public: - // static bool enableColors = true; - void debug(std::string filename, int line, std::string submodule, const char *format, ...) - { + virtual void debug(std::string filename, int line, std::string submodule, + const char* format, ...) = 0; + virtual void error(std::string filename, int line, std::string submodule, + const char* format, ...) = 0; + virtual void info(std::string filename, int line, std::string submodule, + const char* format, ...) = 0; +}; - printf(colorRed); - printf("D "); - if (enableSubmodule) { - printf(colorReset); - printf("[%s] ", submodule.c_str()); - } - printFilename(filename); - printf(":%d: ", line); - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); - printf("\n"); - }; +extern bell::AbstractLogger* bellGlobalLogger; +class BellLogger : public bell::AbstractLogger { + public: + // static bool enableColors = true; + void debug(std::string filename, int line, std::string submodule, + const char* format, ...) { + printTimestamp(); - void error(std::string filename, int line, std::string submodule, const char *format, ...) - { + printf(colorRed); + printf("D "); + if (enableSubmodule) { + printf(colorReset); + printf("[%s] ", submodule.c_str()); + } + printFilename(filename); + printf(":%d: ", line); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + }; - printf(colorRed); - printf("E "); - if (enableSubmodule) { - printf(colorReset); - printf("[%s] ", submodule.c_str()); - } - printFilename(filename); - printf(":%d: ", line); - printf(colorRed); - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); - printf("\n"); - }; + void error(std::string filename, int line, std::string submodule, + const char* format, ...) { + printTimestamp(); - void info(std::string filename, int line, std::string submodule, const char *format, ...) - { + printf(colorRed); + printf("E "); + if (enableSubmodule) { + printf(colorReset); + printf("[%s] ", submodule.c_str()); + } + printFilename(filename); + printf(":%d: ", line); + printf(colorRed); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + }; - printf(colorBlue); - printf("I "); - if (enableSubmodule) { - printf(colorReset); - printf("[%s] ", submodule.c_str()); - } - printFilename(filename); - printf(":%d: ", line); - printf(colorReset); - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); - printf("\n"); - }; + void info(std::string filename, int line, std::string submodule, + const char* format, ...) { + printTimestamp(); - void printFilename(std::string filename) - { + printf(colorBlue); + printf("I "); + if (enableSubmodule) { + printf(colorReset); + printf("[%s] ", submodule.c_str()); + } + printFilename(filename); + printf(":%d: ", line); + printf(colorReset); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + }; + + void printTimestamp() { + if (enableTimestamp) { + auto now = std::chrono::system_clock::now(); + time_t now_time = std::chrono::system_clock::to_time_t(now); + const auto nowMs = std::chrono::duration_cast( + now.time_since_epoch()) % + 1000; + + auto gmt_time = gmtime(&now_time); + printf(colorReset); + std::cout << std::put_time(gmt_time, "[%Y-%m-%d %H:%M:%S") << '.' + << std::setfill('0') << std::setw(3) << nowMs.count() << "] "; + } + } + + void printFilename(std::string filename) { #ifdef _WIN32 - std::string basenameStr(filename.substr(filename.rfind("\\") + 1)); + std::string basenameStr(filename.substr(filename.rfind("\\") + 1)); #else - std::string basenameStr(filename.substr(filename.rfind("/") + 1)); + std::string basenameStr(filename.substr(filename.rfind("/") + 1)); #endif - unsigned long hash = 5381; - for (char const &c : basenameStr) - { - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - } + unsigned long hash = 5381; + for (char const& c : basenameStr) { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + } - printf("\033[0;%dm", allColors[hash % NColors]); + printf("\033[0;%dm", allColors[hash % NColors]); - printf("%s", basenameStr.c_str()); - printf(colorReset); - } + printf("%s", basenameStr.c_str()); + printf(colorReset); + } - private: - static constexpr const char *colorReset = "\033[0m"; - static constexpr const char *colorRed = "\033[0;31m"; - static constexpr const char *colorBlue = "\033[0;34m"; - static constexpr const int NColors = 15; - static constexpr int allColors[NColors] = {31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97}; - }; + private: + static constexpr const char* colorReset = "\033[0m"; + static constexpr const char* colorRed = "\033[0;31m"; + static constexpr const char* colorBlue = "\033[0;34m"; + static constexpr const int NColors = 15; + static constexpr int allColors[NColors] = {31, 32, 33, 34, 35, 36, 37, 90, + 91, 92, 93, 94, 95, 96, 97}; +}; - void setDefaultLogger(); - void enableSubmoduleLogging(); -} +void setDefaultLogger(); +void enableSubmoduleLogging(); +void enableTimestampLogging(); +} // namespace bell -#define BELL_LOG(type, ...) \ - do \ - { \ - bell::bellGlobalLogger->type(__FILE__, __LINE__, __VA_ARGS__); \ - } while (0) +#define BELL_LOG(type, ...) \ + do { \ + bell::bellGlobalLogger->type(__FILE__, __LINE__, __VA_ARGS__); \ + } while (0) -#endif \ No newline at end of file +#endif diff --git a/components/spotify/cspot/bell/main/utilities/include/BellTask.h b/components/spotify/cspot/bell/main/utilities/include/BellTask.h index b549fa4a..7f0fc3be 100644 --- a/components/spotify/cspot/bell/main/utilities/include/BellTask.h +++ b/components/spotify/cspot/bell/main/utilities/include/BellTask.h @@ -15,8 +15,8 @@ #include #endif -#include #include +#include namespace bell { class Task { diff --git a/components/spotify/cspot/bell/main/utilities/include/BellUtils.h b/components/spotify/cspot/bell/main/utilities/include/BellUtils.h index ac6921cd..c196368c 100644 --- a/components/spotify/cspot/bell/main/utilities/include/BellUtils.h +++ b/components/spotify/cspot/bell/main/utilities/include/BellUtils.h @@ -1,14 +1,16 @@ #ifndef EUPHONIUM_BELL_UTILS #define EUPHONIUM_BELL_UTILS -#include +#include // for int32_t, int64_t +#include // for NULL #ifdef _WIN32 #include #else -#include +#include // for timeval, gettimeofday +#include // for usleep #endif -#include -#include +#include // for floor +#include // for string #ifdef ESP_PLATFORM #include "esp_system.h" @@ -28,9 +30,9 @@ struct tv { #if _WIN32 static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); - SYSTEMTIME system_time; - FILETIME file_time; - uint64_t time; + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; GetSystemTime(&system_time); SystemTimeToFileTime(&system_time, &file_time); @@ -50,7 +52,9 @@ struct tv { int32_t sec; int32_t usec; - int64_t ms() { return (sec * (int64_t)1000) + (usec / 1000); } + int64_t ms() { + return (sec * (int64_t)1000) + (usec / 1000); + } tv operator+(const tv& other) const { tv result(*this); @@ -95,7 +99,6 @@ struct tv { #define BELL_SLEEP_MS(ms) Sleep(ms) #define BELL_YIELD() ; #else -#include #define BELL_SLEEP_MS(ms) usleep(ms * 1000) #define BELL_YIELD() ; diff --git a/components/spotify/cspot/bell/main/utilities/include/Crypto.h b/components/spotify/cspot/bell/main/utilities/include/Crypto.h index bafb5f07..503e0cca 100644 --- a/components/spotify/cspot/bell/main/utilities/include/Crypto.h +++ b/components/spotify/cspot/bell/main/utilities/include/Crypto.h @@ -1,83 +1,76 @@ #ifndef BELL_CRYPTO_H #define BELL_CRYPTO_H -#define Crypto CryptoMbedTLS - -#include -#include -#include -#include - -extern "C" { -#include "aes.h" -} -#include -#include -#include -#include -#include -#include -#include +#include // for string +#include // for vector +#include // for mbedtls_aes_context +#include // for mbedtls_md_context_t +#include // for size_t +#include // for uint8_t #define DH_KEY_SIZE 96 const static unsigned char DHPrime[] = { /* Well-known Group 1, 768-bit prime */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, - 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, - 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, - 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, - 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, - 0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, - 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, - 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, - 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, - 0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, + 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, + 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, + 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, + 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, + 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, + 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, + 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static unsigned char DHGenerator[1] = {2}; class CryptoMbedTLS { -private: - mbedtls_md_context_t sha1Context; - mbedtls_aes_context aesCtx; - bool aesCtxInitialized = false; -public: - CryptoMbedTLS(); - ~CryptoMbedTLS(); - // Base64 - std::vector base64Decode(const std::string& data); - std::string base64Encode(const std::vector& data); + private: + mbedtls_md_context_t sha1Context; + mbedtls_aes_context aesCtx; + bool aesCtxInitialized = false; - // Sha1 - void sha1Init(); - void sha1Update(const std::string& s); - void sha1Update(const std::vector& vec); - std::string sha1Final(); - std::vector sha1FinalBytes(); + public: + CryptoMbedTLS(); + ~CryptoMbedTLS(); + // Base64 + std::vector base64Decode(const std::string& data); + std::string base64Encode(const std::vector& data); - // HMAC SHA1 - std::vector sha1HMAC(const std::vector& inputKey, const std::vector& message); + // Sha1 + void sha1Init(); + void sha1Update(const std::string& s); + void sha1Update(const std::vector& vec); + std::string sha1Final(); + std::vector sha1FinalBytes(); - // AES CTR - void aesCTRXcrypt(const std::vector& key, std::vector& iv, uint8_t* data, size_t nbytes); - - // AES ECB - void aesECBdecrypt(const std::vector& key, std::vector& data); + // HMAC SHA1 + std::vector sha1HMAC(const std::vector& inputKey, + const std::vector& message); - // Diffie Hellman - std::vector publicKey; - std::vector privateKey; - void dhInit(); - std::vector dhCalculateShared(const std::vector& remoteKey); + // AES CTR + void aesCTRXcrypt(const std::vector& key, std::vector& iv, + uint8_t* data, size_t nbytes); - // PBKDF2 - std::vector pbkdf2HmacSha1(const std::vector& password, const std::vector& salt, int iterations, int digestSize); + // AES ECB + void aesECBdecrypt(const std::vector& key, + std::vector& data); - // Random stuff - std::vector generateVectorWithRandomData(size_t length); + // Diffie Hellman + std::vector publicKey; + std::vector privateKey; + void dhInit(); + std::vector dhCalculateShared(const std::vector& remoteKey); + + // PBKDF2 + std::vector pbkdf2HmacSha1(const std::vector& password, + const std::vector& salt, + int iterations, int digestSize); + + // Random stuff + std::vector generateVectorWithRandomData(size_t length); }; +#define Crypto CryptoMbedTLS + #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/utilities/include/NanoPBHelper.h b/components/spotify/cspot/bell/main/utilities/include/NanoPBHelper.h index f0c68eb5..f488a7c5 100644 --- a/components/spotify/cspot/bell/main/utilities/include/NanoPBHelper.h +++ b/components/spotify/cspot/bell/main/utilities/include/NanoPBHelper.h @@ -1,47 +1,51 @@ #pragma once -#include -#include "pb_encode.h" -#include "pb_decode.h" -#include +#include // for uint8_t +#include // for printf +#include // for string +#include // for vector -std::vector pbEncode(const pb_msgdesc_t *fields, const void *src_struct); +#include "pb.h" // for pb_msgdesc_t, pb_bytes_array_t, PB_GET_ERROR +#include "pb_decode.h" // for pb_istream_from_buffer, pb_decode, pb_istream_s + +std::vector pbEncode(const pb_msgdesc_t* fields, + const void* src_struct); pb_bytes_array_t* vectorToPbArray(const std::vector& vectorToPack); -void packString(char* &dst, std::string stringToPack); +void packString(char*& dst, std::string stringToPack); std::vector pbArrayToVector(pb_bytes_array_t* pbArray); template -T pbDecode(const pb_msgdesc_t *fields, std::vector &data) -{ +T pbDecode(const pb_msgdesc_t* fields, std::vector& data) { - T result = {}; - // Create stream - pb_istream_t stream = pb_istream_from_buffer(&data[0], data.size()); - - // Decode the message - if (pb_decode(&stream, fields, &result) == false) { - printf("Decode failed: %s\n", PB_GET_ERROR(&stream)); - } - return result; + T result = {}; + // Create stream + pb_istream_t stream = pb_istream_from_buffer(&data[0], data.size()); + + // Decode the message + if (pb_decode(&stream, fields, &result) == false) { + printf("Decode failed: %s\n", PB_GET_ERROR(&stream)); + } + + return result; } template -void pbDecode(T &result, const pb_msgdesc_t *fields, std::vector &data) -{ - // Create stream - pb_istream_t stream = pb_istream_from_buffer(&data[0], data.size()); - - // Decode the message - if (pb_decode(&stream, fields, &result) == false) { - printf("Decode failed: %s\n", PB_GET_ERROR(&stream)); - } +void pbDecode(T& result, const pb_msgdesc_t* fields, + std::vector& data) { + // Create stream + pb_istream_t stream = pb_istream_from_buffer(&data[0], data.size()); + + // Decode the message + if (pb_decode(&stream, fields, &result) == false) { + printf("Decode failed: %s\n", PB_GET_ERROR(&stream)); + } } -void pbPutString(const std::string &stringToPack, char* dst); -void pbPutCharArray(const char * stringToPack, char* dst); -void pbPutBytes(const std::vector &data, pb_bytes_array_t &dst); +void pbPutString(const std::string& stringToPack, char* dst); +void pbPutCharArray(const char* stringToPack, char* dst); +void pbPutBytes(const std::vector& data, pb_bytes_array_t& dst); -const char* pb_encode_to_string(const pb_msgdesc_t *fields, const void *data); +const char* pb_encode_to_string(const pb_msgdesc_t* fields, const void* data); diff --git a/components/spotify/cspot/bell/main/utilities/include/Queue.h b/components/spotify/cspot/bell/main/utilities/include/Queue.h index ae938ea2..80b3c0b8 100644 --- a/components/spotify/cspot/bell/main/utilities/include/Queue.h +++ b/components/spotify/cspot/bell/main/utilities/include/Queue.h @@ -1,117 +1,101 @@ #ifndef BELL_QUEUE_H #define BELL_QUEUE_H -#include #include #include -#include +#include -namespace bell -{ - template - class Queue - { - private: - /// Queue - std::queue m_queue; - /// Mutex to controll multiple access - mutable std::mutex m_mutex; - /// Conditional variable used to fire event - std::condition_variable m_cv; - /// Atomic variable used to terminate immediately wpop and wtpop functions - std::atomic m_forceExit = false; +namespace bell { +template +class Queue { + private: + /// Queue + std::queue m_queue; + /// Mutex to controll multiple access + mutable std::mutex m_mutex; + /// Conditional variable used to fire event + std::condition_variable m_cv; + /// Atomic variable used to terminate immediately wpop and wtpop functions + std::atomic m_forceExit = false; - public: - /// Add a new element in the queue. - /// New element. - void push(dataType const &data) - { - m_forceExit.store(false); - std::unique_lock lk(m_mutex); - m_queue.push(data); - lk.unlock(); - m_cv.notify_one(); - } - /// Check queue empty. - /// True if the queue is empty. - bool isEmpty() const - { - std::unique_lock lk(m_mutex); - return m_queue.empty(); - } - /// Pop element from queue. - /// [in,out] Element. - /// false if the queue is empty. - bool pop(dataType &popped_value) - { - std::unique_lock lk(m_mutex); - if (m_queue.empty()) - { - return false; - } - else - { - popped_value = m_queue.front(); - m_queue.pop(); - return true; - } - } - /// Wait and pop an element in the queue. - /// [in,out] Element. - /// False for forced exit. - bool wpop(dataType &popped_value) - { - std::unique_lock lk(m_mutex); - m_cv.wait(lk, [&]() -> bool - { return !m_queue.empty() || m_forceExit.load(); }); - if (m_forceExit.load()) - return false; - popped_value = m_queue.front(); - m_queue.pop(); - return true; - } - /// Timed wait and pop an element in the queue. - /// [in,out] Element. - /// [in] Wait time. - /// False for timeout or forced exit. - bool wtpop(dataType &popped_value, long milliseconds = 1000) - { - std::unique_lock lk(m_mutex); - m_cv.wait_for(lk, std::chrono::milliseconds(milliseconds), [&]() -> bool - { return !m_queue.empty() || m_forceExit.load(); }); - if (m_forceExit.load()) - return false; - if (m_queue.empty()) - return false; - popped_value = m_queue.front(); - m_queue.pop(); - return true; - } - /// Queue size. - int size() - { - std::unique_lock lk(m_mutex); - return static_cast(m_queue.size()); - } - /// Free the queue and force stop. - void clear() - { - m_forceExit.store(true); - std::unique_lock lk(m_mutex); - while (!m_queue.empty()) - { - //delete m_queue.front(); - m_queue.pop(); - } - lk.unlock(); - m_cv.notify_one(); - } - /// Check queue in forced exit state. - bool isExit() const - { - return m_forceExit.load(); - } - }; -} + public: + /// Add a new element in the queue. + /// New element. + void push(dataType const& data) { + m_forceExit.store(false); + std::unique_lock lk(m_mutex); + m_queue.push(data); + lk.unlock(); + m_cv.notify_one(); + } + /// Check queue empty. + /// True if the queue is empty. + bool isEmpty() const { + std::unique_lock lk(m_mutex); + return m_queue.empty(); + } + /// Pop element from queue. + /// [in,out] Element. + /// false if the queue is empty. + bool pop(dataType& popped_value) { + std::unique_lock lk(m_mutex); + if (m_queue.empty()) { + return false; + } else { + popped_value = m_queue.front(); + m_queue.pop(); + return true; + } + } + /// Wait and pop an element in the queue. + /// [in,out] Element. + /// False for forced exit. + bool wpop(dataType& popped_value) { + std::unique_lock lk(m_mutex); + m_cv.wait(lk, + [&]() -> bool { return !m_queue.empty() || m_forceExit.load(); }); + if (m_forceExit.load()) + return false; + popped_value = m_queue.front(); + m_queue.pop(); + return true; + } + /// Timed wait and pop an element in the queue. + /// [in,out] Element. + /// [in] Wait time. + /// False for timeout or forced exit. + bool wtpop(dataType& popped_value, long milliseconds = 1000) { + std::unique_lock lk(m_mutex); + m_cv.wait_for(lk, std::chrono::milliseconds(milliseconds), [&]() -> bool { + return !m_queue.empty() || m_forceExit.load(); + }); + if (m_forceExit.load()) + return false; + if (m_queue.empty()) + return false; + popped_value = m_queue.front(); + m_queue.pop(); + return true; + } + /// Queue size. + int size() { + std::unique_lock lk(m_mutex); + return static_cast(m_queue.size()); + } + /// Free the queue and force stop. + void clear() { + m_forceExit.store(true); + std::unique_lock lk(m_mutex); + while (!m_queue.empty()) { + //delete m_queue.front(); + m_queue.pop(); + } + lk.unlock(); + m_cv.notify_one(); + } + /// Check queue in forced exit state. + bool isExit() const { return m_forceExit.load(); } +}; +} // namespace bell #endif \ No newline at end of file diff --git a/components/spotify/cspot/bell/main/utilities/include/TimeDefs.h b/components/spotify/cspot/bell/main/utilities/include/TimeDefs.h index 21d602ab..8299b679 100644 --- a/components/spotify/cspot/bell/main/utilities/include/TimeDefs.h +++ b/components/spotify/cspot/bell/main/utilities/include/TimeDefs.h @@ -5,4 +5,4 @@ #ifndef EUPHONIUMCLI_TIMEDEFS_H #define EUPHONIUMCLI_TIMEDEFS_H -#endif // EUPHONIUMCLI_TIMEDEFS_H +#endif // EUPHONIUMCLI_TIMEDEFS_H diff --git a/components/spotify/cspot/bell/main/utilities/include/aes.h b/components/spotify/cspot/bell/main/utilities/include/aes.h index 3a24bd28..3eba21de 100644 --- a/components/spotify/cspot/bell/main/utilities/include/aes.h +++ b/components/spotify/cspot/bell/main/utilities/include/aes.h @@ -1,8 +1,8 @@ #ifndef _AES_H_ #define _AES_H_ -#include #include +#include // #define the macros below to 1/0 to enable/disable the mode of operation. // @@ -12,37 +12,35 @@ // The #ifndef-guard allows it to be configured before #include'ing or at compile time. #ifndef CBC - #define CBC 1 +#define CBC 1 #endif #ifndef ECB - #define ECB 1 +#define ECB 1 #endif #ifndef CTR - #define CTR 1 +#define CTR 1 #endif - // #define AES128 1 #define AES192 1 //#define AES256 1 -#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only +#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only #if defined(AES256) && (AES256 == 1) - #define AES_KEYLEN 32 - #define AES_keyExpSize 240 +#define AES_KEYLEN 32 +#define AES_keyExpSize 240 #elif defined(AES192) && (AES192 == 1) - #define AES_KEYLEN 24 - #define AES_keyExpSize 208 +#define AES_KEYLEN 24 +#define AES_keyExpSize 208 #else - #define AES_KEYLEN 16 // Key length in bytes - #define AES_keyExpSize 176 +#define AES_KEYLEN 16 // Key length in bytes +#define AES_keyExpSize 176 #endif -struct AES_ctx -{ +struct AES_ctx { uint8_t RoundKey[AES_keyExpSize]; #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) uint8_t Iv[AES_BLOCKLEN]; @@ -51,41 +49,39 @@ struct AES_ctx void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); #if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) -void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, + const uint8_t* iv); void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); #endif #if defined(ECB) && (ECB == 1) -// buffer size is exactly AES_BLOCKLEN bytes; -// you need only AES_init_ctx as IV is not used in ECB +// buffer size is exactly AES_BLOCKLEN bytes; +// you need only AES_init_ctx as IV is not used in ECB // NB: ECB is considered insecure for most uses void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); -#endif // #if defined(ECB) && (ECB == !) - +#endif // #if defined(ECB) && (ECB == !) #if defined(CBC) && (CBC == 1) // buffer size MUST be mutile of AES_BLOCKLEN; // Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme // NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() -// no IV should ever be reused with the same key +// no IV should ever be reused with the same key void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); -#endif // #if defined(CBC) && (CBC == 1) - +#endif // #if defined(CBC) && (CBC == 1) #if defined(CTR) && (CTR == 1) -// Same function for encrypting as for decrypting. +// Same function for encrypting as for decrypting. // IV is incremented for every block, and used after encryption as XOR-compliment for output // Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme // NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() -// no IV should ever be reused with the same key +// no IV should ever be reused with the same key void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length); -#endif // #if defined(CTR) && (CTR == 1) +#endif // #if defined(CTR) && (CTR == 1) - -#endif // _AES_H_ \ No newline at end of file +#endif // _AES_H_ \ No newline at end of file diff --git a/components/spotify/cspot/include/AccessKeyFetcher.h b/components/spotify/cspot/include/AccessKeyFetcher.h index 11e5a73c..949c1461 100644 --- a/components/spotify/cspot/include/AccessKeyFetcher.h +++ b/components/spotify/cspot/include/AccessKeyFetcher.h @@ -3,29 +3,41 @@ #include // for function #include // for shared_ptr #include // for string +#include +namespace bell { +class WrappedSemaphore; +}; namespace cspot { struct Context; class AccessKeyFetcher { public: AccessKeyFetcher(std::shared_ptr ctx); - ~AccessKeyFetcher(); - typedef std::function Callback; + /** + * @brief Checks if key is expired + * @returns true when currently held access key is not valid + */ + bool isExpired(); - void getAccessKey(Callback callback); + /** + * @brief Fetches a new access key + * @remark In case the key is expired, this function blocks until a refresh is done. + * @returns access key + */ + std::string getAccessKey(); + + /** + * @brief Forces a refresh of the access key + */ + void updateAccessKey(); private: - const std::string CLIENT_ID = - "65b708073fc0480ea92a077233ca87bd"; // Spotify web client's client id - const std::string SCOPES = - "streaming,user-library-read,user-library-modify,user-top-read,user-read-" - "recently-played"; // Required access scopes - std::shared_ptr ctx; + std::shared_ptr updateSemaphore; - bool isExpired(); + std::atomic keyPending = false; std::string accessKey; long long int expiresAt; }; diff --git a/components/spotify/cspot/include/ApResolve.h b/components/spotify/cspot/include/ApResolve.h index 13b282a9..fafb4485 100644 --- a/components/spotify/cspot/include/ApResolve.h +++ b/components/spotify/cspot/include/ApResolve.h @@ -8,17 +8,16 @@ namespace cspot { class ApResolve { - private: - std::string apOverride; - public: ApResolve(std::string apOverride); /** - * @brief Connects to spotify's servers and returns first valid ap address - * - * @return std::string Address in form of url:port - */ + * @brief Connects to spotify's servers and returns first valid ap address + * @returns std::string Address in form of url:port + */ std::string fetchFirstApAddress(); + + private: + std::string apOverride; }; } // namespace cspot diff --git a/components/spotify/cspot/include/AuthChallenges.h b/components/spotify/cspot/include/AuthChallenges.h index 38d5a161..379f2e7c 100644 --- a/components/spotify/cspot/include/AuthChallenges.h +++ b/components/spotify/cspot/include/AuthChallenges.h @@ -1,10 +1,9 @@ #pragma once - -#include // for uint8_t -#include // for unique_ptr -#include // for string -#include // for vector +#include // for uint8_t +#include // for unique_ptr +#include // for string +#include // for vector #include "Crypto.h" // for Crypto #include "protobuf/authentication.pb.h" // for ClientResponseEncrypted @@ -16,20 +15,45 @@ class AuthChallenges { AuthChallenges(); ~AuthChallenges(); - std::vector shanSendKey = {}; - std::vector shanRecvKey = {}; - + /** + * @brief Prepares a spotify authentication packet + * @param authBlob authentication blob bytes + * @param authType value representing spotify's authentication type + * @param deviceId device id to use during auth. + * @param username spotify's username + * + * @returns vector containing bytes of the authentication packet + */ std::vector prepareAuthPacket(std::vector& authBlob, int authType, const std::string& deviceId, const std::string& username); + + /** + * @brief Solves the ApHello packet, and returns a packet with response + * + * @param helloPacket hello packet bytes received from the server + * @param data authentication data received from the server + * + * @returns vector containing response packet + */ std::vector solveApHello(std::vector& helloPacket, std::vector& data); + /** + * @brief Prepares an client hello packet, used for initial auth with spotify + * + * @returns vector containing the packet's data + */ std::vector prepareClientHello(); + std::vector shanSendKey = {}; + std::vector shanRecvKey = {}; + private: const long long SPOTIFY_VERSION = 0x10800000000; + + // Protobuf structures ClientResponseEncrypted authRequest; ClientResponsePlaintext clientResPlaintext; ClientHello clientHello; @@ -37,4 +61,4 @@ class AuthChallenges { std::unique_ptr crypto; }; -} // namespace cspot \ No newline at end of file +} // namespace cspot diff --git a/components/spotify/cspot/include/CSpotContext.h b/components/spotify/cspot/include/CSpotContext.h index 0237da85..ae1c77d2 100644 --- a/components/spotify/cspot/include/CSpotContext.h +++ b/components/spotify/cspot/include/CSpotContext.h @@ -2,10 +2,10 @@ #include +#include "LoginBlob.h" #include "MercurySession.h" #include "TimeProvider.h" #include "protobuf/metadata.pb.h" -#include "LoginBlob.h" namespace cspot { struct Context { @@ -25,7 +25,8 @@ struct Context { std::shared_ptr timeProvider; std::shared_ptr session; - static std::shared_ptr createFromBlob(std::shared_ptr blob) { + static std::shared_ptr createFromBlob( + std::shared_ptr blob) { auto ctx = std::make_shared(); ctx->timeProvider = std::make_shared(); @@ -37,6 +38,5 @@ struct Context { return ctx; } - }; -} // namespace cspot \ No newline at end of file +} // namespace cspot diff --git a/components/spotify/cspot/include/ConstantParameters.h b/components/spotify/cspot/include/ConstantParameters.h index 7cdd5495..12ebac30 100644 --- a/components/spotify/cspot/include/ConstantParameters.h +++ b/components/spotify/cspot/include/ConstantParameters.h @@ -7,11 +7,11 @@ extern char deviceId[]; namespace cspot { // Hardcoded information sent to spotify servers -const char * const informationString = "cspot-player"; -const char * const brandName = "cspot"; -const char * const versionString = "cspot-1.1"; -const char * const protocolVersion = "2.7.1"; -const char * const defaultDeviceName = "CSpot"; -const char * const swVersion = "1.0.0"; +const char* const informationString = "cspot-player"; +const char* const brandName = "cspot"; +const char* const versionString = "cspot-1.1"; +const char* const protocolVersion = "2.7.1"; +const char* const defaultDeviceName = "CSpot"; +const char* const swVersion = "1.0.0"; -} \ No newline at end of file +} // namespace cspot \ No newline at end of file diff --git a/components/spotify/cspot/include/CspotAssert.h b/components/spotify/cspot/include/CspotAssert.h index de535984..ca0dd8fd 100644 --- a/components/spotify/cspot/include/CspotAssert.h +++ b/components/spotify/cspot/include/CspotAssert.h @@ -3,14 +3,13 @@ #include #include -#define CSPOT_ASSERT(CONDITION, MESSAGE) \ - do \ - { \ - if (!(CONDITION)) \ - { \ - printf("At %s in %s:%d\n Assertion %s failed: %s", __func__, __FILE__, __LINE__, #CONDITION, MESSAGE); \ - abort(); \ - } \ - } while (0) +#define CSPOT_ASSERT(CONDITION, MESSAGE) \ + do { \ + if (!(CONDITION)) { \ + printf("At %s in %s:%d\n Assertion %s failed: %s", __func__, __FILE__, \ + __LINE__, #CONDITION, MESSAGE); \ + abort(); \ + } \ + } while (0) #endif diff --git a/components/spotify/cspot/include/Logger.h b/components/spotify/cspot/include/Logger.h index 40c3c333..60864ff8 100644 --- a/components/spotify/cspot/include/Logger.h +++ b/components/spotify/cspot/include/Logger.h @@ -2,8 +2,7 @@ #include -#define CSPOT_LOG(type, ...) \ - do \ - { \ - bell::bellGlobalLogger->type(__FILE__, __LINE__, "cspot", __VA_ARGS__); \ - } while (0) +#define CSPOT_LOG(type, ...) \ + do { \ + bell::bellGlobalLogger->type(__FILE__, __LINE__, "cspot", __VA_ARGS__); \ + } while (0) diff --git a/components/spotify/cspot/include/LoginBlob.h b/components/spotify/cspot/include/LoginBlob.h index 2a1f3611..0a8bb00b 100644 --- a/components/spotify/cspot/include/LoginBlob.h +++ b/components/spotify/cspot/include/LoginBlob.h @@ -1,10 +1,10 @@ #pragma once -#include // for uint8_t, uint32_t -#include // for map -#include // for unique_ptr -#include // for string -#include // for vector +#include // for uint8_t, uint32_t +#include // for map +#include // for unique_ptr +#include // for string +#include // for vector #include "Crypto.h" // for CryptoMbedTLS, Crypto diff --git a/components/spotify/cspot/include/MercurySession.h b/components/spotify/cspot/include/MercurySession.h index 4f4126e7..07496cc2 100644 --- a/components/spotify/cspot/include/MercurySession.h +++ b/components/spotify/cspot/include/MercurySession.h @@ -1,13 +1,13 @@ #pragma once -#include // for atomic -#include // for uint8_t, uint64_t, uint32_t -#include // for function -#include // for shared_ptr -#include // for mutex -#include // for string -#include // for unordered_map -#include // for vector +#include // for atomic +#include // for uint8_t, uint64_t, uint32_t +#include // for function +#include // for shared_ptr +#include // for mutex +#include // for string +#include // for unordered_map +#include // for vector #include "BellTask.h" // for Task #include "Packet.h" // for Packet @@ -15,7 +15,7 @@ #include "Session.h" // for Session #include "protobuf/mercury.pb.h" // for Header -namespace cspot { +namespace cspot { class TimeProvider; class MercurySession : public bell::Task, public cspot::Session { @@ -33,7 +33,8 @@ class MercurySession : public bell::Task, public cspot::Session { }; typedef std::function ResponseCallback; - typedef std::function&)> AudioKeyCallback; + typedef std::function&)> + AudioKeyCallback; typedef std::function ConnectionEstabilishedCallback; enum class RequestType : uint8_t { @@ -82,7 +83,11 @@ class MercurySession : public bell::Task, public cspot::Session { return this->executeSubscription(type, uri, callback, nullptr, parts); } - void requestAudioKey(const std::vector& trackId, + void unregister(uint64_t sequenceId); + + void unregisterAudioKey(uint32_t sequenceId); + + uint32_t requestAudioKey(const std::vector& trackId, const std::vector& fileId, AudioKeyCallback audioCallback); @@ -108,7 +113,7 @@ class MercurySession : public bell::Task, public cspot::Session { std::unordered_map callbacks; std::unordered_map subscriptions; - AudioKeyCallback audioKeyCallback; + std::unordered_map audioKeyCallbacks; uint64_t sequenceId = 1; uint32_t audioKeySequence = 1; diff --git a/components/spotify/cspot/include/PlainConnection.h b/components/spotify/cspot/include/PlainConnection.h index 6bb37b47..0bd735cc 100644 --- a/components/spotify/cspot/include/PlainConnection.h +++ b/components/spotify/cspot/include/PlainConnection.h @@ -6,7 +6,7 @@ #include "win32shim.h" #else -#include // for size_t +#include // for size_t #endif #include // for uint8_t #include // for function @@ -37,8 +37,8 @@ class PlainConnection { void readBlock(const uint8_t* dst, size_t size); size_t writeBlock(const std::vector& data); - private: - int apSock; + private: + int apSock; }; } // namespace cspot diff --git a/components/spotify/cspot/include/PlaybackState.h b/components/spotify/cspot/include/PlaybackState.h index b13fd71e..a79eab01 100644 --- a/components/spotify/cspot/include/PlaybackState.h +++ b/components/spotify/cspot/include/PlaybackState.h @@ -1,10 +1,11 @@ #pragma once -#include // for uint8_t, uint32_t -#include // for shared_ptr -#include // for string -#include // for vector +#include // for uint8_t, uint32_t +#include // for shared_ptr +#include // for string +#include // for vector +#include "TrackReference.h" #include "protobuf/spirc.pb.h" // for Frame, TrackRef, CapabilityType, Mess... namespace cspot { @@ -13,8 +14,10 @@ struct Context; class PlaybackState { private: std::shared_ptr ctx; + uint32_t seqNum = 0; uint8_t capabilityIndex = 0; + std::vector frameData; void addCapability( @@ -24,6 +27,9 @@ class PlaybackState { public: Frame innerFrame; Frame remoteFrame; + + std::vector remoteTracks; + enum class State { Playing, Stopped, Loading, Paused }; /** @@ -74,56 +80,9 @@ class PlaybackState { void setVolume(uint32_t volume); /** - * @brief Enables queue shuffling. - * - * Sets shuffle parameter on local frame, and in case shuffling is enabled, - * it will randomize the entire local queue. - * - * @param shuffle whenever should shuffle + * @brief Updates local track queue from remote data. */ - void setShuffle(bool shuffle); - - /** - * @brief Enables repeat - * - * @param repeat should repeat param - */ - void setRepeat(bool repeat); - - /** - * @brief Updates local track queue from remote data. - */ - void updateTracks(); - - /** - * @brief Changes playback to next queued track. - * - * Will go back to first track if current track is last track in queue. - * In that case, it will pause if repeat is disabled. - */ - bool nextTrack(); - - /** - * @brief Changes playback to previous queued track. - * - * Will stop if current track is the first track in queue and repeat is disabled. - * If repeat is enabled, it will loop back to the last track in queue. - */ - void prevTrack(); - - /** - * @brief Gets the current track reference. - * - * @return std::shared_ptr pointer to track reference - */ - TrackRef* getCurrentTrackRef(); - - /** - * @brief Gets reference to next track in queue, or nullptr if there is no next track. - * - * @return std::shared_ptr pointer to track reference - */ - TrackRef* getNextTrackRef(); + void syncWithRemote(); /** * @brief Encodes current frame into binary data via protobuf. @@ -132,5 +91,7 @@ class PlaybackState { * @return std::vector binary frame data */ std::vector encodeCurrentFrame(MessageType typ); + + bool decodeRemoteFrame(std::vector& data); }; -} // namespace cspot \ No newline at end of file +} // namespace cspot diff --git a/components/spotify/cspot/include/Shannon.h b/components/spotify/cspot/include/Shannon.h index aa19bdb8..23e9f172 100644 --- a/components/spotify/cspot/include/Shannon.h +++ b/components/spotify/cspot/include/Shannon.h @@ -4,41 +4,40 @@ #include // for uint32_t, uint8_t #include // for vector -class Shannon -{ -public: - static constexpr unsigned int N = 16; +class Shannon { + public: + static constexpr unsigned int N = 16; - void key(const std::vector &key); /* set key */ - void nonce(const std::vector &nonce); /* set Init Vector */ - void stream(std::vector &buf); /* stream cipher */ - void maconly(std::vector &buf); /* accumulate MAC */ - void encrypt(std::vector &buf); /* encrypt + MAC */ - void decrypt(std::vector &buf); /* finalize + MAC */ - void finish(std::vector &buf); /* finalise MAC */ + void key(const std::vector& key); /* set key */ + void nonce(const std::vector& nonce); /* set Init Vector */ + void stream(std::vector& buf); /* stream cipher */ + void maconly(std::vector& buf); /* accumulate MAC */ + void encrypt(std::vector& buf); /* encrypt + MAC */ + void decrypt(std::vector& buf); /* finalize + MAC */ + void finish(std::vector& buf); /* finalise MAC */ -private: - static constexpr unsigned int FOLD = Shannon::N; - static constexpr unsigned int INITKONST = 0x6996c53a; - static constexpr unsigned int KEYP = 13; - uint32_t R[Shannon::N]; - uint32_t CRC[Shannon::N]; - uint32_t initR[Shannon::N]; - uint32_t konst; - uint32_t sbuf; - uint32_t mbuf; - int nbuf; - static uint32_t sbox1(uint32_t w); - static uint32_t sbox2(uint32_t w); - void cycle(); - void crcfunc(uint32_t i); - void macfunc(uint32_t i); - void initState(); - void saveState(); - void reloadState(); - void genkonst(); - void diffuse(); - void loadKey(const std::vector &key); + private: + static constexpr unsigned int FOLD = Shannon::N; + static constexpr unsigned int INITKONST = 0x6996c53a; + static constexpr unsigned int KEYP = 13; + uint32_t R[Shannon::N]; + uint32_t CRC[Shannon::N]; + uint32_t initR[Shannon::N]; + uint32_t konst; + uint32_t sbuf; + uint32_t mbuf; + int nbuf; + static uint32_t sbox1(uint32_t w); + static uint32_t sbox2(uint32_t w); + void cycle(); + void crcfunc(uint32_t i); + void macfunc(uint32_t i); + void initState(); + void saveState(); + void reloadState(); + void genkonst(); + void diffuse(); + void loadKey(const std::vector& key); }; #endif \ No newline at end of file diff --git a/components/spotify/cspot/include/ShannonConnection.h b/components/spotify/cspot/include/ShannonConnection.h index b1a1fd01..30a8cbac 100644 --- a/components/spotify/cspot/include/ShannonConnection.h +++ b/components/spotify/cspot/include/ShannonConnection.h @@ -1,10 +1,10 @@ #ifndef SHANNONCONNECTION_H #define SHANNONCONNECTION_H -#include // for uint8_t, uint32_t -#include // for shared_ptr, unique_ptr -#include // for mutex -#include // for vector +#include // for uint8_t, uint32_t +#include // for shared_ptr, unique_ptr +#include // for mutex +#include // for vector #include "Packet.h" // for Packet diff --git a/components/spotify/cspot/include/SpircHandler.h b/components/spotify/cspot/include/SpircHandler.h index 5401088b..ecb21082 100644 --- a/components/spotify/cspot/include/SpircHandler.h +++ b/components/spotify/cspot/include/SpircHandler.h @@ -1,14 +1,14 @@ #pragma once -#include // for uint32_t, uint8_t -#include // for function -#include // for shared_ptr, unique_ptr -#include // for string -#include // for variant -#include // for vector +#include // for uint32_t, uint8_t +#include // for function +#include // for shared_ptr, unique_ptr +#include // for string +#include // for variant +#include // for vector -#include "CDNTrackStream.h" // for CDNTrackStream, CDNTrackStream::Track... -#include "PlaybackState.h" // for PlaybackState +#include "CDNAudioFile.h" // for CDNTrackStream, CDNTrackStream::Track... +#include "TrackQueue.h" #include "protobuf/spirc.pb.h" // for MessageType namespace cspot { @@ -31,7 +31,8 @@ class SpircHandler { FLUSH, PLAYBACK_START }; - typedef std::variant EventData; + + typedef std::variant EventData; struct Event { EventType eventType; @@ -47,36 +48,34 @@ class SpircHandler { void setPause(bool pause); - void nextSong(); void previousSong(); + void nextSong(); + void notifyAudioReachedPlayback(); void updatePositionMs(uint32_t position); void setRemoteVolume(int volume); void loadTrackFromURI(const std::string& uri); + std::shared_ptr getTrackQueue() { return trackQueue; } void disconnect(); private: std::shared_ptr ctx; std::shared_ptr trackPlayer; + std::shared_ptr trackQueue; EventHandler eventHandler = nullptr; - cspot::PlaybackState playbackState; - CDNTrackStream::TrackInfo currentTrackInfo; - - bool isTrackFresh = true; - bool isRequestedFromLoad = false; - bool isNextTrackPreloaded = false; - uint32_t nextTrackPosition = 0; + std::shared_ptr playbackState; void sendCmd(MessageType typ); void sendEvent(EventType type); void sendEvent(EventType type, EventData data); + void skipSong(TrackQueue::SkipDirection dir); void handleFrame(std::vector& data); void notify(); }; -} // namespace cspot \ No newline at end of file +} // namespace cspot diff --git a/components/spotify/cspot/include/TrackPlayer.h b/components/spotify/cspot/include/TrackPlayer.h index 5eaf9f50..74735ab4 100644 --- a/components/spotify/cspot/include/TrackPlayer.h +++ b/components/spotify/cspot/include/TrackPlayer.h @@ -1,47 +1,54 @@ #pragma once -#include // for atomic -#include // for uint8_t, int64_t -#include // for size_t, time -#include // for function -#include // for shared_ptr, unique_ptr -#include // for mutex -#include // for string_view -#include // for vector +#include // for atomic +#include // for uint8_t, int64_t +#include // for size_t, time +#include // for function +#include // for shared_ptr, unique_ptr +#include // for mutex +#include // for string_view +#include // for vector -#include "BellTask.h" // for Task -#include "CDNTrackStream.h" // for CDNTrackStream, CDNTrackStream::TrackInfo +#include "BellTask.h" // for Task +#include "CDNAudioFile.h" +#include "TrackQueue.h" namespace bell { class WrappedSemaphore; } // namespace bell + #ifdef BELL_VORBIS_FLOAT #include "vorbis/vorbisfile.h" #else -#include "ivorbisfile.h" // for OggVorbis_File, ov_callbacks +#include "ivorbisfile.h" // for OggVorbis_File, ov_callbacks #endif namespace cspot { class TrackProvider; +class TrackQueue; struct Context; struct TrackReference; class TrackPlayer : bell::Task { public: - typedef std::function TrackLoadedCallback; - typedef std::function DataCallback; + // Callback types + typedef std::function)> TrackLoadedCallback; + typedef std::function DataCallback; typedef std::function EOFCallback; typedef std::function isAiringCallback; - TrackPlayer(std::shared_ptr ctx, isAiringCallback, EOFCallback, TrackLoadedCallback); + TrackPlayer(std::shared_ptr ctx, + std::shared_ptr trackQueue, + EOFCallback eofCallback, TrackLoadedCallback loadedCallback); ~TrackPlayer(); - - void loadTrackFromRef(TrackReference& ref, size_t playbackMs, bool startAutomatically); + + void loadTrackFromRef(TrackReference& ref, size_t playbackMs, + bool startAutomatically); void setDataCallback(DataCallback callback); - - CDNTrackStream::TrackInfo getCurrentTrackInfo(); + + // CDNTrackStream::TrackInfo getCurrentTrackInfo(); void seekMs(size_t ms); - void stopTrack(); + void resetState(); // Vorbis codec callbacks size_t _vorbisRead(void* ptr, size_t size, size_t nmemb); @@ -49,35 +56,39 @@ class TrackPlayer : bell::Task { int _vorbisSeek(int64_t offset, int whence); long _vorbisTell(); - void destroy(); + void stop(); + void start(); private: std::shared_ptr ctx; - std::shared_ptr trackProvider; - std::shared_ptr currentTrackStream; - size_t sequence = std::time(nullptr); + std::shared_ptr trackQueue; + std::shared_ptr currentTrackStream; std::unique_ptr playbackSemaphore; TrackLoadedCallback trackLoaded; DataCallback dataCallback = nullptr; EOFCallback eofCallback; - isAiringCallback isAiring; // Playback control std::atomic currentSongPlaying; std::mutex playbackMutex; - std::mutex seekMutex; - + std::mutex dataOutMutex; + // Vorbis related OggVorbis_File vorbisFile; ov_callbacks vorbisCallbacks; int currentSection; + std::vector pcmBuffer = std::vector(1024); - size_t playbackPosition = 0; bool autoStart = false; - std::atomic isRunning = true; + + std::atomic isRunning = false; + std::atomic pendingReset = false; + std::atomic inFuture = false; + std::atomic pendingSeekPositionMs = 0; + std::mutex runningMutex; void runTask() override; diff --git a/components/spotify/cspot/include/TrackReference.h b/components/spotify/cspot/include/TrackReference.h index ec87e16c..a1ede7be 100644 --- a/components/spotify/cspot/include/TrackReference.h +++ b/components/spotify/cspot/include/TrackReference.h @@ -1,51 +1,36 @@ #pragma once +#include #include #include +#include #include "NanoPBHelper.h" -#include "Utils.h" +#include "pb_decode.h" #include "protobuf/spirc.pb.h" -namespace cspot { +namespace cspot { struct TrackReference { - static constexpr auto base62Alphabet = - "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + TrackReference(); // Resolved track GID std::vector gid; + std::string uri, context; + std::optional queued; // Type identifier enum class Type { TRACK, EPISODE }; + Type type; - static TrackReference fromTrackRef(TrackRef* ref) { - TrackReference trackRef; - if (ref->gid != nullptr) { - // For tracks, the GID is already in the protobuf - trackRef.gid = pbArrayToVector(ref->gid); - trackRef.type = Type::TRACK; - } else { - // Episode GID is being fetched via base62 encoded URI - auto uri = std::string(ref->uri); - auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size()); - trackRef.gid = {0}; + void decodeURI(); - std::string_view alphabet(base62Alphabet); - for (int x = 0; x < idString.size(); x++) { - size_t d = alphabet.find(idString[x]); - trackRef.gid = bigNumMultiply(trackRef.gid, 62); - trackRef.gid = bigNumAdd(trackRef.gid, d); - } - } + bool operator==(const TrackReference& other) const; - return trackRef; - } + // Encodes list of track references into a pb structure, used by nanopb + static bool pbEncodeTrackList(pb_ostream_t* stream, const pb_field_t* field, + void* const* arg); - static TrackReference fromGID(std::vector gid, bool isEpisode) { - TrackReference trackRef; - trackRef.gid = gid; - trackRef.type = isEpisode ? Type::EPISODE : Type::TRACK; - return trackRef; - } + static bool pbDecodeTrackList(pb_istream_t* stream, const pb_field_t* field, + void** arg); }; -} // namespace cspot \ No newline at end of file +} // namespace cspot diff --git a/components/spotify/cspot/include/Utils.h b/components/spotify/cspot/include/Utils.h index 95dcce11..a52be4ea 100644 --- a/components/spotify/cspot/include/Utils.h +++ b/components/spotify/cspot/include/Utils.h @@ -1,7 +1,7 @@ #ifndef UTILS_H #define UTILS_H -#include // for snprintf, size_t -#include // for vector +#include // for snprintf, size_t +#include // for vector #ifdef _WIN32 #include #include @@ -55,7 +55,6 @@ std::vector bigNumAdd(std::vector num, int n); unsigned char h2int(char c); - std::string urlDecode(std::string str); /** @@ -64,7 +63,7 @@ std::string urlDecode(std::string str); * @param s string containing hex data * @return std::vector vector containing binary data */ -std::vector stringHexToBytes(const std::string &s); +std::vector stringHexToBytes(const std::string& s); /** * @brief Converts provided bytes into a human readable hex string @@ -72,7 +71,7 @@ std::vector stringHexToBytes(const std::string &s); * @param bytes vector containing binary data * @return std::string string containing hex representation of inputted data */ -std::string bytesToHexString(const std::vector &bytes); +std::string bytesToHexString(const std::vector& bytes); /** * @brief Extracts given type from binary data @@ -83,8 +82,7 @@ std::string bytesToHexString(const std::vector &bytes); * @return T extracted type */ template -T extract(const std::vector &v, int pos) -{ +T extract(const std::vector& v, int pos) { T value; memcpy(&value, &v[pos], sizeof(T)); return value; @@ -98,22 +96,25 @@ T extract(const std::vector &v, int pos) * @return std::vector resulting vector containing binary data */ template -std::vector pack(T data) -{ - std::vector rawData( (std::uint8_t*)&data, (std::uint8_t*)&(data) + sizeof(T)); +std::vector pack(T data) { + std::vector rawData((std::uint8_t*)&data, + (std::uint8_t*)&(data) + sizeof(T)); - return rawData; + return rawData; } -template -std::string string_format( const std::string& format, Args ... args ) -{ - int size_s = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' - if( size_s <= 0 ){ throw std::runtime_error( "Error during formatting." ); } - auto size = static_cast( size_s ); - std::unique_ptr buf( new char[ size ] ); - std::snprintf( buf.get(), size, format.c_str(), args ... ); - return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside +template +std::string string_format(const std::string& format, Args... args) { + int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + + 1; // Extra space for '\0' + if (size_s <= 0) { + throw std::runtime_error("Error during formatting."); + } + auto size = static_cast(size_s); + std::unique_ptr buf(new char[size]); + std::snprintf(buf.get(), size, format.c_str(), args...); + return std::string(buf.get(), + buf.get() + size - 1); // We don't want the '\0' inside } #endif \ No newline at end of file diff --git a/components/spotify/cspot/protobuf/spirc.options b/components/spotify/cspot/protobuf/spirc.options index 3ed13c47..b7331f53 100644 --- a/components/spotify/cspot/protobuf/spirc.options +++ b/components/spotify/cspot/protobuf/spirc.options @@ -7,7 +7,4 @@ DeviceState.sw_version type:FT_POINTER DeviceState.name type:FT_POINTER DeviceState.capabilities max_count:17, fixed_count:false State.context_uri type:FT_POINTER -State.track type:FT_POINTER -TrackRef.gid type:FT_POINTER -TrackRef.uri type:FT_POINTER -TrackRef.context type:FT_POINTER \ No newline at end of file +TrackRef.queued type:FT_CALLBACK \ No newline at end of file diff --git a/components/spotify/cspot/protobuf/spirc.proto b/components/spotify/cspot/protobuf/spirc.proto index 4339949c..5d54bd26 100644 --- a/components/spotify/cspot/protobuf/spirc.proto +++ b/components/spotify/cspot/protobuf/spirc.proto @@ -58,6 +58,10 @@ enum CapabilityType { kVolumeSteps = 0x8; kSupportedTypes = 0x9; kCommandAcks = 0xa; + kSupportsRename = 0xb; + kHidden = 0xc; + kSupportsPlaylistV2 = 0xd; + kSupportsExternalEpisodes = 0xe; } message Capability { diff --git a/components/spotify/cspot/src/AccessKeyFetcher.cpp b/components/spotify/cspot/src/AccessKeyFetcher.cpp index d3d32237..968522c5 100644 --- a/components/spotify/cspot/src/AccessKeyFetcher.cpp +++ b/components/spotify/cspot/src/AccessKeyFetcher.cpp @@ -6,13 +6,14 @@ #include // for remove_extent_t #include // for vector -#include "BellLogger.h" // for AbstractLogger -#include "CSpotContext.h" // for Context -#include "Logger.h" // for CSPOT_LOG -#include "MercurySession.h" // for MercurySession, MercurySession::Res... -#include "Packet.h" // for cspot -#include "TimeProvider.h" // for TimeProvider -#include "Utils.h" // for string_format +#include "BellLogger.h" // for AbstractLogger +#include "CSpotContext.h" // for Context +#include "Logger.h" // for CSPOT_LOG +#include "MercurySession.h" // for MercurySession, MercurySession::Res... +#include "Packet.h" // for cspot +#include "TimeProvider.h" // for TimeProvider +#include "Utils.h" // for string_format +#include "WrappedSemaphore.h" #ifdef BELL_ONLY_CJSON #include "cJSON.h" #else @@ -22,11 +23,17 @@ using namespace cspot; -AccessKeyFetcher::AccessKeyFetcher(std::shared_ptr ctx) { - this->ctx = ctx; -} +static std::string CLIENT_ID = + "65b708073fc0480ea92a077233ca87bd"; // Spotify web client's client id -AccessKeyFetcher::~AccessKeyFetcher() {} +static std::string SCOPES = + "streaming,user-library-read,user-library-modify,user-top-read,user-read-" + "recently-played"; // Required access scopes + +AccessKeyFetcher::AccessKeyFetcher(std::shared_ptr ctx) + : ctx(ctx) { + this->updateSemaphore = std::make_shared(); +} bool AccessKeyFetcher::isExpired() { if (accessKey.empty()) { @@ -40,11 +47,24 @@ bool AccessKeyFetcher::isExpired() { return false; } -void AccessKeyFetcher::getAccessKey(AccessKeyFetcher::Callback callback) { +std::string AccessKeyFetcher::getAccessKey() { if (!isExpired()) { - return callback(accessKey); + return accessKey; } + updateAccessKey(); + + return accessKey; +} + +void AccessKeyFetcher::updateAccessKey() { + if (keyPending) { + // Already pending refresh request + return; + } + + keyPending = true; + CSPOT_LOG(info, "Access token expired, fetching new one..."); std::string url = @@ -54,17 +74,17 @@ void AccessKeyFetcher::getAccessKey(AccessKeyFetcher::Callback callback) { ctx->session->execute( MercurySession::RequestType::GET, url, - [this, timeProvider, callback](MercurySession::Response& res) { + [this, timeProvider](MercurySession::Response& res) { if (res.fail) return; - char* accessKeyJson = (char*)res.parts[0].data(); - auto accessJSON = std::string( - accessKeyJson, strrchr(accessKeyJson, '}') - accessKeyJson + 1); + auto accessJSON = + std::string((char*)res.parts[0].data(), res.parts[0].size()); #ifdef BELL_ONLY_CJSON cJSON* jsonBody = cJSON_Parse(accessJSON.c_str()); this->accessKey = cJSON_GetObjectItem(jsonBody, "accessToken")->valuestring; int expiresIn = cJSON_GetObjectItem(jsonBody, "expiresIn")->valueint; + cJSON_Delete(jsonBody); #else auto jsonBody = nlohmann::json::parse(accessJSON); this->accessKey = jsonBody["accessToken"]; @@ -74,11 +94,11 @@ void AccessKeyFetcher::getAccessKey(AccessKeyFetcher::Callback callback) { this->expiresAt = timeProvider->getSyncedTimestamp() + (expiresIn * 1000); -#ifdef BELL_ONLY_CJSON - callback(cJSON_GetObjectItem(jsonBody, "accessToken")->valuestring); - cJSON_Delete(jsonBody); -#else - callback(jsonBody["accessToken"]); -#endif + updateSemaphore->give(); }); + + updateSemaphore->twait(5000); + + // Mark as not pending for refresh + keyPending = false; } diff --git a/components/spotify/cspot/src/ApResolve.cpp b/components/spotify/cspot/src/ApResolve.cpp index 011f1c23..ba455e9d 100644 --- a/components/spotify/cspot/src/ApResolve.cpp +++ b/components/spotify/cspot/src/ApResolve.cpp @@ -1,10 +1,10 @@ #include "ApResolve.h" -#include // for initializer_list -#include // for operator!=, operator== -#include // for allocator, unique_ptr -#include // for string_view -#include // for vector +#include // for initializer_list +#include // for operator!=, operator== +#include // for allocator, unique_ptr +#include // for string_view +#include // for vector #include "HTTPClient.h" // for HTTPClient, HTTPClient::Response #ifdef BELL_ONLY_CJSON @@ -16,29 +16,27 @@ using namespace cspot; -ApResolve::ApResolve(std::string apOverride) -{ - this->apOverride = apOverride; +ApResolve::ApResolve(std::string apOverride) { + this->apOverride = apOverride; } -std::string ApResolve::fetchFirstApAddress() -{ - if (apOverride != "") - { - return apOverride; - } +std::string ApResolve::fetchFirstApAddress() { + if (apOverride != "") { + return apOverride; + } - auto request = bell::HTTPClient::get("https://apresolve.spotify.com/"); - std::string_view responseStr = request->body(); + auto request = bell::HTTPClient::get("https://apresolve.spotify.com/"); + std::string_view responseStr = request->body(); - // parse json with nlohmann + // parse json with nlohmann #ifdef BELL_ONLY_CJSON - cJSON* json = cJSON_Parse(responseStr.data()); - auto ap_string = std::string(cJSON_GetArrayItem(cJSON_GetObjectItem(json, "ap_list"), 0)->valuestring); - cJSON_Delete(json); - return ap_string; -#else - auto json = nlohmann::json::parse(responseStr); - return json["ap_list"][0]; -#endif + cJSON* json = cJSON_Parse(responseStr.data()); + auto ap_string = std::string( + cJSON_GetArrayItem(cJSON_GetObjectItem(json, "ap_list"), 0)->valuestring); + cJSON_Delete(json); + return ap_string; +#else + auto json = nlohmann::json::parse(responseStr); + return json["ap_list"][0]; +#endif } diff --git a/components/spotify/cspot/src/AuthChallenges.cpp b/components/spotify/cspot/src/AuthChallenges.cpp index b1b48509..633d9fa4 100644 --- a/components/spotify/cspot/src/AuthChallenges.cpp +++ b/components/spotify/cspot/src/AuthChallenges.cpp @@ -1,8 +1,8 @@ #include "AuthChallenges.h" -#include // for copy -#include // for CHAR_BIT -#include // for default_random_engine, independent_bits_en... +#include // for copy +#include // for CHAR_BIT +#include // for default_random_engine, independent_bits_en... #include "NanoPBHelper.h" // for pbPutString, pbEncode, pbDecode #include "pb.h" // for pb_byte_t @@ -94,9 +94,9 @@ std::vector AuthChallenges::solveApHello( // Get send and receive keys this->shanSendKey = std::vector(resultData.begin() + 0x14, - resultData.begin() + 0x34); + resultData.begin() + 0x34); this->shanRecvKey = std::vector(resultData.begin() + 0x34, - resultData.begin() + 0x54); + resultData.begin() + 0x54); return pbEncode(ClientResponsePlaintext_fields, &clientResPlaintext); } @@ -125,5 +125,6 @@ std::vector AuthChallenges::prepareClientHello() { // Generate the random nonce auto nonce = crypto->generateVectorWithRandomData(16); std::copy(nonce.begin(), nonce.end(), clientHello.client_nonce); + return pbEncode(ClientHello_fields, &clientHello); -} \ No newline at end of file +} diff --git a/components/spotify/cspot/src/LoginBlob.cpp b/components/spotify/cspot/src/LoginBlob.cpp index 4a1d8ca7..fb2cf919 100644 --- a/components/spotify/cspot/src/LoginBlob.cpp +++ b/components/spotify/cspot/src/LoginBlob.cpp @@ -1,18 +1,18 @@ #include "LoginBlob.h" -#include // for sprintf -#include // for initializer_list +#include // for sprintf +#include // for initializer_list #include "BellLogger.h" // for AbstractLogger #include "ConstantParameters.h" // for brandName, cspot, protoc... #include "Logger.h" // for CSPOT_LOG #include "protobuf/authentication.pb.h" // for AuthenticationType_AUTHE... #ifdef BELL_ONLY_CJSON -#include "cJSON.h" +#include "cJSON.h " #else #include "nlohmann/detail/json_pointer.hpp" // for json_pointer<>::string_t -#include "nlohmann/json.hpp" // for basic_json<>::object_t -#include "nlohmann/json_fwd.hpp" // for json +#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json +#include "nlohmann/json_fwd.hpp" // for json #endif using namespace cspot; @@ -24,7 +24,7 @@ LoginBlob::LoginBlob(std::string name) { this->deviceId = std::string("142137fd329622137a149016") + std::string(hash); this->crypto = std::make_unique(); this->name = name; - + this->crypto->dhInit(); } @@ -142,7 +142,8 @@ void LoginBlob::loadJson(const std::string& json) { cJSON* root = cJSON_Parse(json.c_str()); this->authType = cJSON_GetObjectItem(root, "authType")->valueint; this->username = cJSON_GetObjectItem(root, "username")->valuestring; - std::string authDataObject = cJSON_GetObjectItem(root, "authData")->valuestring; + std::string authDataObject = + cJSON_GetObjectItem(root, "authData")->valuestring; cJSON_Delete(root); #else auto root = nlohmann::json::parse(json); @@ -151,23 +152,24 @@ void LoginBlob::loadJson(const std::string& json) { std::string authDataObject = root["authData"]; this->authData = crypto->base64Decode(authDataObject); -#endif +#endif } std::string LoginBlob::toJson() { #ifdef BELL_ONLY_CJSON - cJSON* json_obj = cJSON_CreateObject(); - cJSON_AddStringToObject(json_obj, "authData", crypto->base64Encode(authData).c_str()); + cJSON* json_obj = cJSON_CreateObject(); + cJSON_AddStringToObject(json_obj, "authData", + crypto->base64Encode(authData).c_str()); cJSON_AddNumberToObject(json_obj, "authType", this->authType); cJSON_AddStringToObject(json_obj, "username", this->username.c_str()); - - char *str = cJSON_PrintUnformatted(json_obj); - cJSON_Delete(json_obj); + + char* str = cJSON_PrintUnformatted(json_obj); + cJSON_Delete(json_obj); std::string json_objStr(str); free(str); - + return json_objStr; -#else +#else nlohmann::json obj; obj["authData"] = crypto->base64Encode(authData); obj["authType"] = this->authType; @@ -200,7 +202,7 @@ std::string LoginBlob::buildZeroconfInfo() { auto encodedKey = crypto->base64Encode(crypto->publicKey); #ifdef BELL_ONLY_CJSON - cJSON* json_obj = cJSON_CreateObject(); + cJSON* json_obj = cJSON_CreateObject(); cJSON_AddNumberToObject(json_obj, "status", 101); cJSON_AddStringToObject(json_obj, "statusString", "OK"); cJSON_AddStringToObject(json_obj, "version", cspot::protocolVersion); @@ -214,20 +216,21 @@ std::string LoginBlob::buildZeroconfInfo() { cJSON_AddStringToObject(json_obj, "tokenType", "default"); cJSON_AddStringToObject(json_obj, "groupStatus", "NONE"); cJSON_AddStringToObject(json_obj, "resolverVersion", "0"); - cJSON_AddStringToObject(json_obj, "scope", "streaming,client-authorization-universal"); - cJSON_AddStringToObject(json_obj, "activeUser", ""); - cJSON_AddStringToObject(json_obj, "deviceID", deviceId.c_str()); - cJSON_AddStringToObject(json_obj, "remoteName", name.c_str()); - cJSON_AddStringToObject(json_obj, "publicKey", encodedKey.c_str()); - cJSON_AddStringToObject(json_obj, "deviceType", "deviceType"); - - char *str = cJSON_PrintUnformatted(json_obj); - cJSON_Delete(json_obj); + cJSON_AddStringToObject(json_obj, "scope", + "streaming,client-authorization-universal"); + cJSON_AddStringToObject(json_obj, "activeUser", ""); + cJSON_AddStringToObject(json_obj, "deviceID", deviceId.c_str()); + cJSON_AddStringToObject(json_obj, "remoteName", name.c_str()); + cJSON_AddStringToObject(json_obj, "publicKey", encodedKey.c_str()); + cJSON_AddStringToObject(json_obj, "deviceType", "deviceType"); + + char* str = cJSON_PrintUnformatted(json_obj); + cJSON_Delete(json_obj); std::string json_objStr(str); free(str); - + return json_objStr; -#else +#else nlohmann::json obj; obj["status"] = 101; obj["statusString"] = "OK"; diff --git a/components/spotify/cspot/src/MercurySession.cpp b/components/spotify/cspot/src/MercurySession.cpp index 6778cb76..605ac924 100644 --- a/components/spotify/cspot/src/MercurySession.cpp +++ b/components/spotify/cspot/src/MercurySession.cpp @@ -6,11 +6,9 @@ #include // for runtime_error #include // for remove_extent_t, __underlying_type_impl<>:... #include // for pair - #ifndef _WIN32 -#include +#include // for htons, ntohs, htonl, ntohl #endif - #include "BellLogger.h" // for AbstractLogger #include "BellTask.h" // for Task #include "BellUtils.h" // for BELL_SLEEP_MS @@ -110,6 +108,22 @@ bool MercurySession::triggerTimeout() { return false; } +void MercurySession::unregister(uint64_t sequenceId) { + auto callback = this->callbacks.find(sequenceId); + + if (callback != this->callbacks.end()) { + this->callbacks.erase(callback); + } +} + +void MercurySession::unregisterAudioKey(uint32_t sequenceId) { + auto callback = this->audioKeyCallbacks.find(sequenceId); + + if (callback != this->audioKeyCallbacks.end()) { + this->audioKeyCallbacks.erase(callback); + } +} + void MercurySession::disconnect() { CSPOT_LOG(info, "Disconnecting mercury session"); this->isRunning = false; @@ -145,12 +159,13 @@ void MercurySession::handlePacket() { // First four bytes mark the sequence id auto seqId = ntohl(extract(packet.data, 0)); - if (seqId == (this->audioKeySequence - 1) && - audioKeyCallback != nullptr) { + + if (this->audioKeyCallbacks.count(seqId) > 0) { auto success = static_cast(packet.command) == RequestType::AUDIO_KEY_SUCCESS_RESPONSE; - audioKeyCallback(success, packet.data); + this->audioKeyCallbacks[seqId](success, packet.data); } + break; } case RequestType::SEND: @@ -290,23 +305,30 @@ uint64_t MercurySession::executeSubscription(RequestType method, // Bump sequence id this->sequenceId += 1; - this->shanConn->sendPacket( - static_cast::type>(method), - sequenceIdBytes); + try { + this->shanConn->sendPacket( + static_cast::type>(method), + sequenceIdBytes); + } catch (...) { + // @TODO: handle disconnect + } return this->sequenceId - 1; } -void MercurySession::requestAudioKey(const std::vector& trackId, - const std::vector& fileId, - AudioKeyCallback audioCallback) { +uint32_t MercurySession::requestAudioKey(const std::vector& trackId, + const std::vector& fileId, + AudioKeyCallback audioCallback) { auto buffer = fileId; - this->audioKeyCallback = audioCallback; + + // Store callback + this->audioKeyCallbacks.insert({this->audioKeySequence, audioCallback}); // Structure: [FILEID] [TRACKID] [4 BYTES SEQUENCE ID] [0x00, 0x00] buffer.insert(buffer.end(), trackId.begin(), trackId.end()); - auto audioKeySequence = pack(htonl(this->audioKeySequence)); - buffer.insert(buffer.end(), audioKeySequence.begin(), audioKeySequence.end()); + auto audioKeySequenceBuffer = pack(htonl(this->audioKeySequence)); + buffer.insert(buffer.end(), audioKeySequenceBuffer.begin(), + audioKeySequenceBuffer.end()); auto suffix = std::vector({0x00, 0x00}); buffer.insert(buffer.end(), suffix.begin(), suffix.end()); @@ -315,6 +337,11 @@ void MercurySession::requestAudioKey(const std::vector& trackId, // Used for broken connection detection // this->lastRequestTimestamp = timeProvider->getSyncedTimestamp(); - this->shanConn->sendPacket( - static_cast(RequestType::AUDIO_KEY_REQUEST_COMMAND), buffer); + try { + this->shanConn->sendPacket( + static_cast(RequestType::AUDIO_KEY_REQUEST_COMMAND), buffer); + } catch (...) { + // @TODO: Handle disconnect + } + return audioKeySequence - 1; } diff --git a/components/spotify/cspot/src/PlainConnection.cpp b/components/spotify/cspot/src/PlainConnection.cpp index 4ccb4eff..7337f691 100644 --- a/components/spotify/cspot/src/PlainConnection.cpp +++ b/components/spotify/cspot/src/PlainConnection.cpp @@ -1,19 +1,17 @@ #include "PlainConnection.h" #ifndef _WIN32 -#include // for addrinfo, freeaddrinfo, getaddrinfo -#include // for IPPROTO_IP, IPPROTO_TCP -#include // for EAGAIN, EINTR, ETIMEDOUT, errno -#include // for setsockopt, connect, recv, send, shutdown -#include // for timeval -#endif -#include // for memset -#include // for runtime_error -#ifdef _WIN32 -#include -#else +#include // for addrinfo, freeaddrinfo, getaddrinfo +#include // for IPPROTO_IP, IPPROTO_TCP +#include // for EAGAIN, EINTR, ETIMEDOUT, errno +#include // for setsockopt, connect, recv, send, shutdown +#include // for timeval +#include // for memset +#include // for runtime_error #include // for TCP_NODELAY -#include +#include +#else +#include #endif #include "BellLogger.h" // for AbstractLogger #include "Logger.h" // for CSPOT_LOG @@ -67,8 +65,8 @@ void PlainConnection::connect(const std::string& apAddress) { if (this->apSock < 0) continue; - if (::connect(this->apSock, (struct sockaddr*)ai->ai_addr, ai->ai_addrlen) != - -1) { + if (::connect(this->apSock, (struct sockaddr*)ai->ai_addr, + ai->ai_addrlen) != -1) { #ifdef _WIN32 uint32_t tv = 3000; #else @@ -144,10 +142,10 @@ void PlainConnection::readBlock(const uint8_t* dst, size_t size) { switch (getErrno()) { case EAGAIN: case ETIMEDOUT: - // if (timeoutHandler()) { - // CSPOT_LOG(error, "Connection lost, will need to reconnect..."); - // throw std::runtime_error("Reconnection required"); - // } + if (timeoutHandler()) { + CSPOT_LOG(error, "Connection lost, will need to reconnect..."); + throw std::runtime_error("Reconnection required"); + } goto READ; case EINTR: break; @@ -174,9 +172,9 @@ size_t PlainConnection::writeBlock(const std::vector& data) { switch (getErrno()) { case EAGAIN: case ETIMEDOUT: - // if (timeoutHandler()) { - // throw std::runtime_error("Reconnection required"); - // } + if (timeoutHandler()) { + throw std::runtime_error("Reconnection required"); + } goto WRITE; case EINTR: break; diff --git a/components/spotify/cspot/src/PlaybackState.cpp b/components/spotify/cspot/src/PlaybackState.cpp index fd8d7a41..72697c2f 100644 --- a/components/spotify/cspot/src/PlaybackState.cpp +++ b/components/spotify/cspot/src/PlaybackState.cpp @@ -1,11 +1,12 @@ #include "PlaybackState.h" -#include // for strdup, memcpy, strcpy, strlen -#include // for uint8_t -#include // for free, NULL, realloc, rand -#include // for shared_ptr -#include // for remove_extent_t -#include // for swap +#include // for strdup, memcpy, strcpy, strlen +#include // for uint8_t +#include // for free, NULL, realloc, rand +#include +#include // for shared_ptr +#include // for remove_extent_t +#include // for swap #include "BellLogger.h" // for AbstractLogger #include "CSpotContext.h" // for Context::ConfigState, Context (ptr o... @@ -15,6 +16,7 @@ #include "Packet.h" // for cspot #include "pb.h" // for pb_bytes_array_t, PB_BYTES_ARRAY_T_A... #include "pb_decode.h" // for pb_release +#include "protobuf/spirc.pb.h" using namespace cspot; @@ -23,6 +25,13 @@ PlaybackState::PlaybackState(std::shared_ptr ctx) { innerFrame = {}; remoteFrame = {}; + // Prepare callbacks for decoding of remote frame track data + remoteFrame.state.track.funcs.decode = &TrackReference::pbDecodeTrackList; + remoteFrame.state.track.arg = &remoteTracks; + + innerFrame.ident = strdup(ctx->config.deviceId.c_str()); + innerFrame.protocol_version = strdup(protocolVersion); + // Prepare default state innerFrame.state.has_position_ms = true; innerFrame.state.position_ms = 0; @@ -52,13 +61,12 @@ PlaybackState::PlaybackState(std::shared_ptr ctx) { innerFrame.device_state.name = strdup(ctx->config.deviceName.c_str()); - innerFrame.state.track_count = 0; - // Prepare player's capabilities addCapability(CapabilityType_kCanBePlayer, 1); addCapability(CapabilityType_kDeviceType, 4); addCapability(CapabilityType_kGaiaEqConnectId, 1); addCapability(CapabilityType_kSupportsLogout, 0); + addCapability(CapabilityType_kSupportsPlaylistV2, 1); addCapability(CapabilityType_kIsObservable, 1); addCapability(CapabilityType_kVolumeSteps, 64); addCapability(CapabilityType_kSupportedContexts, -1, @@ -66,8 +74,8 @@ PlaybackState::PlaybackState(std::shared_ptr ctx) { "inbox", "toplist", "starred", "publishedstarred", "track"})); addCapability(CapabilityType_kSupportedTypes, -1, - std::vector({"audio/local", "audio/track", - "audio/episode", "local", "track"})); + std::vector( + {"audio/track", "audio/episode", "audio/episode+track"})); innerFrame.device_state.capabilities_count = 8; } @@ -102,34 +110,20 @@ void PlaybackState::setPlaybackState(const PlaybackState::State state) { } } +void PlaybackState::syncWithRemote() { + innerFrame.state.context_uri = (char*)realloc( + innerFrame.state.context_uri, strlen(remoteFrame.state.context_uri) + 1); + + strcpy(innerFrame.state.context_uri, remoteFrame.state.context_uri); + + innerFrame.state.has_playing_track_index = true; + innerFrame.state.playing_track_index = remoteFrame.state.playing_track_index; +} + bool PlaybackState::isActive() { return innerFrame.device_state.is_active; } -bool PlaybackState::nextTrack() { - innerFrame.state.playing_track_index++; - - if (innerFrame.state.playing_track_index >= innerFrame.state.track_count) { - - innerFrame.state.playing_track_index = 0; - - if (!innerFrame.state.repeat) { - setPlaybackState(State::Paused); - return false; - } - } - - return true; -} - -void PlaybackState::prevTrack() { - if (innerFrame.state.playing_track_index > 0) { - innerFrame.state.playing_track_index--; - } else if (innerFrame.state.repeat) { - innerFrame.state.playing_track_index = innerFrame.state.track_count - 1; - } -} - void PlaybackState::setActive(bool isActive) { innerFrame.device_state.is_active = isActive; if (isActive) { @@ -145,131 +139,25 @@ void PlaybackState::updatePositionMs(uint32_t position) { ctx->timeProvider->getSyncedTimestamp(); } -#define FREE(ptr) \ - { \ - free(ptr); \ - ptr = NULL; \ - } -#define STRDUP(dst, src) \ - if (src != NULL) { \ - dst = strdup(src); \ - } else { \ - FREE(dst); \ - } // strdup null pointer safe - -void PlaybackState::updateTracks() { - CSPOT_LOG(info, "---- Track count %d", remoteFrame.state.track_count); - CSPOT_LOG(info, "---- Inner track count %d", innerFrame.state.track_count); - CSPOT_LOG(info, "--- Context URI %s", remoteFrame.state.context_uri); - - // free unused tracks - if (innerFrame.state.track_count > remoteFrame.state.track_count) { - for (uint16_t i = remoteFrame.state.track_count; - i < innerFrame.state.track_count; ++i) { - FREE(innerFrame.state.track[i].gid); - FREE(innerFrame.state.track[i].uri); - FREE(innerFrame.state.track[i].context); - } - } - - // reallocate memory for new tracks - innerFrame.state.track = (TrackRef*)realloc( - innerFrame.state.track, sizeof(TrackRef) * remoteFrame.state.track_count); - - for (uint16_t i = 0; i < remoteFrame.state.track_count; ++i) { - if (i >= innerFrame.state.track_count) { - innerFrame.state.track[i].gid = NULL; - innerFrame.state.track[i].uri = NULL; - innerFrame.state.track[i].context = NULL; - } - - if (remoteFrame.state.track[i].gid != NULL) { - uint16_t gid_size = remoteFrame.state.track[i].gid->size; - innerFrame.state.track[i].gid = (pb_bytes_array_t*)realloc( - innerFrame.state.track[i].gid, PB_BYTES_ARRAY_T_ALLOCSIZE(gid_size)); - - memcpy(innerFrame.state.track[i].gid->bytes, - remoteFrame.state.track[i].gid->bytes, gid_size); - innerFrame.state.track[i].gid->size = gid_size; - } - innerFrame.state.track[i].has_queued = - remoteFrame.state.track[i].has_queued; - innerFrame.state.track[i].queued = remoteFrame.state.track[i].queued; - - STRDUP(innerFrame.state.track[i].uri, remoteFrame.state.track[i].uri); - STRDUP(innerFrame.state.track[i].context, - remoteFrame.state.track[i].context); - } - - innerFrame.state.context_uri = (char*)realloc( - innerFrame.state.context_uri, strlen(remoteFrame.state.context_uri) + 1); - strcpy(innerFrame.state.context_uri, remoteFrame.state.context_uri); - - innerFrame.state.track_count = remoteFrame.state.track_count; - innerFrame.state.has_playing_track_index = true; - innerFrame.state.playing_track_index = remoteFrame.state.playing_track_index; - - if (remoteFrame.state.repeat) { - setRepeat(true); - } - - if (remoteFrame.state.shuffle) { - setShuffle(true); - } -} - void PlaybackState::setVolume(uint32_t volume) { innerFrame.device_state.volume = volume; ctx->config.volume = volume; } -void PlaybackState::setShuffle(bool shuffle) { - innerFrame.state.shuffle = shuffle; - if (shuffle) { - // Put current song at the begining - std::swap(innerFrame.state.track[0], - innerFrame.state.track[innerFrame.state.playing_track_index]); +bool PlaybackState::decodeRemoteFrame(std::vector& data) { + pb_release(Frame_fields, &remoteFrame); - // Shuffle current tracks - for (int x = 1; x < innerFrame.state.track_count - 1; x++) { - auto j = x + (std::rand() % (innerFrame.state.track_count - x)); - std::swap(innerFrame.state.track[j], innerFrame.state.track[x]); - } - innerFrame.state.playing_track_index = 0; - } -} + remoteTracks.clear(); -void PlaybackState::setRepeat(bool repeat) { - innerFrame.state.repeat = repeat; -} + pbDecode(remoteFrame, Frame_fields, data); -TrackRef* PlaybackState::getCurrentTrackRef() { - if (innerFrame.state.playing_track_index >= innerFrame.state.track_count) { - return nullptr; - } - return &innerFrame.state.track[innerFrame.state.playing_track_index]; -} - -TrackRef* PlaybackState::getNextTrackRef() { - if ((innerFrame.state.playing_track_index + 1) >= innerFrame.state.track_count) { - if (innerFrame.state.repeat) { - return &innerFrame.state.track[0]; - } - return nullptr; - } - - return &innerFrame.state.track[innerFrame.state.playing_track_index + 1]; + return true; } std::vector PlaybackState::encodeCurrentFrame(MessageType typ) { - free(innerFrame.ident); - free(innerFrame.protocol_version); - // Prepare current frame info innerFrame.version = 1; - innerFrame.ident = strdup(ctx->config.deviceId.c_str()); innerFrame.seq_nr = this->seqNum; - innerFrame.protocol_version = strdup(protocolVersion); innerFrame.typ = typ; innerFrame.state_update_id = ctx->timeProvider->getSyncedTimestamp(); innerFrame.has_version = true; @@ -281,6 +169,7 @@ std::vector PlaybackState::encodeCurrentFrame(MessageType typ) { innerFrame.has_state_update_id = true; this->seqNum += 1; + return pbEncode(Frame_fields, &innerFrame); } @@ -308,5 +197,6 @@ void PlaybackState::addCapability(CapabilityType typ, int intValue, this->innerFrame.device_state.capabilities[capabilityIndex] .stringValue_count = stringValue.size(); + this->capabilityIndex += 1; } diff --git a/components/spotify/cspot/src/Shannon.cpp b/components/spotify/cspot/src/Shannon.cpp index 37615eee..f6419611 100644 --- a/components/spotify/cspot/src/Shannon.cpp +++ b/components/spotify/cspot/src/Shannon.cpp @@ -5,437 +5,389 @@ using std::size_t; -static inline uint32_t rotl(uint32_t n, unsigned int c) -{ - const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2. - // assert ( (c<=mask) &&"rotate by type width or more"); - c &= mask; - return (n << c) | (n >> ((-c) & mask)); +static inline uint32_t rotl(uint32_t n, unsigned int c) { + const unsigned int mask = + (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2. + // assert ( (c<=mask) &&"rotate by type width or more"); + c &= mask; + return (n << c) | (n >> ((-c) & mask)); } -static inline uint32_t rotr(uint32_t n, unsigned int c) -{ - const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2. - // assert ( (c<=mask) &&"rotate by type width or more"); - c &= mask; - return (n >> c) | (n << ((-c) & mask)); +static inline uint32_t rotr(uint32_t n, unsigned int c) { + const unsigned int mask = + (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2. + // assert ( (c<=mask) &&"rotate by type width or more"); + c &= mask; + return (n >> c) | (n << ((-c) & mask)); } -uint32_t Shannon::sbox1(uint32_t w) -{ - w ^= rotl(w, 5) | rotl(w, 7); - w ^= rotl(w, 19) | rotl(w, 22); - return w; +uint32_t Shannon::sbox1(uint32_t w) { + w ^= rotl(w, 5) | rotl(w, 7); + w ^= rotl(w, 19) | rotl(w, 22); + return w; } -uint32_t Shannon::sbox2(uint32_t w) -{ - w ^= rotl(w, 7) | rotl(w, 22); - w ^= rotl(w, 5) | rotl(w, 19); - return w; +uint32_t Shannon::sbox2(uint32_t w) { + w ^= rotl(w, 7) | rotl(w, 22); + w ^= rotl(w, 5) | rotl(w, 19); + return w; } -void Shannon::cycle() -{ - uint32_t t; - int i; +void Shannon::cycle() { + uint32_t t; + int i; - /* nonlinear feedback function */ - t = this->R[12] ^ this->R[13] ^ this->konst; - t = Shannon::sbox1(t) ^ rotl(this->R[0], 1); - /* shift register */ - for (i = 1; i < N; ++i) - this->R[i - 1] = this->R[i]; - this->R[N - 1] = t; - t = Shannon::sbox2(this->R[2] ^ this->R[15]); - this->R[0] ^= t; - this->sbuf = t ^ this->R[8] ^ this->R[12]; + /* nonlinear feedback function */ + t = this->R[12] ^ this->R[13] ^ this->konst; + t = Shannon::sbox1(t) ^ rotl(this->R[0], 1); + /* shift register */ + for (i = 1; i < N; ++i) + this->R[i - 1] = this->R[i]; + this->R[N - 1] = t; + t = Shannon::sbox2(this->R[2] ^ this->R[15]); + this->R[0] ^= t; + this->sbuf = t ^ this->R[8] ^ this->R[12]; } -void Shannon::crcfunc(uint32_t i) -{ - uint32_t t; - int j; +void Shannon::crcfunc(uint32_t i) { + uint32_t t; + int j; - /* Accumulate CRC of input */ - t = this->CRC[0] ^ this->CRC[2] ^ this->CRC[15] ^ i; - for (j = 1; j < N; ++j) - this->CRC[j - 1] = this->CRC[j]; - this->CRC[N - 1] = t; + /* Accumulate CRC of input */ + t = this->CRC[0] ^ this->CRC[2] ^ this->CRC[15] ^ i; + for (j = 1; j < N; ++j) + this->CRC[j - 1] = this->CRC[j]; + this->CRC[N - 1] = t; } -void Shannon::macfunc(uint32_t i) -{ - this->crcfunc(i); - this->R[KEYP] ^= i; +void Shannon::macfunc(uint32_t i) { + this->crcfunc(i); + this->R[KEYP] ^= i; } -void Shannon::initState() -{ - int i; +void Shannon::initState() { + int i; - /* Register initialised to Fibonacci numbers; Counter zeroed. */ - this->R[0] = 1; - this->R[1] = 1; - for (i = 2; i < N; ++i) - this->R[i] = this->R[i - 1] + this->R[i - 2]; - this->konst = Shannon::INITKONST; + /* Register initialised to Fibonacci numbers; Counter zeroed. */ + this->R[0] = 1; + this->R[1] = 1; + for (i = 2; i < N; ++i) + this->R[i] = this->R[i - 1] + this->R[i - 2]; + this->konst = Shannon::INITKONST; } -void Shannon::saveState() -{ - int i; - for (i = 0; i < Shannon::N; ++i) - this->initR[i] = this->R[i]; +void Shannon::saveState() { + int i; + for (i = 0; i < Shannon::N; ++i) + this->initR[i] = this->R[i]; } -void Shannon::reloadState() -{ - int i; +void Shannon::reloadState() { + int i; - for (i = 0; i < Shannon::N; ++i) - this->R[i] = this->initR[i]; + for (i = 0; i < Shannon::N; ++i) + this->R[i] = this->initR[i]; } -void Shannon::genkonst() -{ - this->konst = this->R[0]; +void Shannon::genkonst() { + this->konst = this->R[0]; } -void Shannon::diffuse() -{ - int i; +void Shannon::diffuse() { + int i; - for (i = 0; i < Shannon::FOLD; ++i) - this->cycle(); + for (i = 0; i < Shannon::FOLD; ++i) + this->cycle(); } #define Byte(x, i) ((uint32_t)(((x) >> (8 * (i))) & 0xFF)) -#define BYTE2WORD(b) ( \ - (((uint32_t)(b)[3] & 0xFF) << 24) | \ - (((uint32_t)(b)[2] & 0xFF) << 16) | \ - (((uint32_t)(b)[1] & 0xFF) << 8) | \ - (((uint32_t)(b)[0] & 0xFF))) -#define WORD2BYTE(w, b) \ - { \ - (b)[3] = Byte(w, 3); \ - (b)[2] = Byte(w, 2); \ - (b)[1] = Byte(w, 1); \ - (b)[0] = Byte(w, 0); \ - } -#define XORWORD(w, b) \ - { \ - (b)[3] ^= Byte(w, 3); \ - (b)[2] ^= Byte(w, 2); \ - (b)[1] ^= Byte(w, 1); \ - (b)[0] ^= Byte(w, 0); \ - } +#define BYTE2WORD(b) \ + ((((uint32_t)(b)[3] & 0xFF) << 24) | (((uint32_t)(b)[2] & 0xFF) << 16) | \ + (((uint32_t)(b)[1] & 0xFF) << 8) | (((uint32_t)(b)[0] & 0xFF))) +#define WORD2BYTE(w, b) \ + { \ + (b)[3] = Byte(w, 3); \ + (b)[2] = Byte(w, 2); \ + (b)[1] = Byte(w, 1); \ + (b)[0] = Byte(w, 0); \ + } +#define XORWORD(w, b) \ + { \ + (b)[3] ^= Byte(w, 3); \ + (b)[2] ^= Byte(w, 2); \ + (b)[1] ^= Byte(w, 1); \ + (b)[0] ^= Byte(w, 0); \ + } -#define XORWORD(w, b) \ - { \ - (b)[3] ^= Byte(w, 3); \ - (b)[2] ^= Byte(w, 2); \ - (b)[1] ^= Byte(w, 1); \ - (b)[0] ^= Byte(w, 0); \ - } +#define XORWORD(w, b) \ + { \ + (b)[3] ^= Byte(w, 3); \ + (b)[2] ^= Byte(w, 2); \ + (b)[1] ^= Byte(w, 1); \ + (b)[0] ^= Byte(w, 0); \ + } /* Load key material into the register */ -#define ADDKEY(k) \ - this->R[KEYP] ^= (k); +#define ADDKEY(k) this->R[KEYP] ^= (k); -void Shannon::loadKey(const std::vector& key) -{ - int i, j; - uint32_t k; - uint8_t xtra[4]; - size_t keylen = key.size(); - /* start folding in key */ - for (i = 0; i < (keylen & ~0x3); i += 4) - { - k = BYTE2WORD(&key[i]); - ADDKEY(k); - this->cycle(); - } - - /* if there were any extra key bytes, zero pad to a word */ - if (i < keylen) - { - for (j = 0 /* i unchanged */; i < keylen; ++i) - xtra[j++] = key[i]; - for (/* j unchanged */; j < 4; ++j) - xtra[j] = 0; - k = BYTE2WORD(xtra); - ADDKEY(k); - this->cycle(); - } - - /* also fold in the length of the key */ - ADDKEY(keylen); +void Shannon::loadKey(const std::vector& key) { + int i, j; + uint32_t k; + uint8_t xtra[4]; + size_t keylen = key.size(); + /* start folding in key */ + for (i = 0; i < (keylen & ~0x3); i += 4) { + k = BYTE2WORD(&key[i]); + ADDKEY(k); this->cycle(); + } - /* save a copy of the register */ - for (i = 0; i < N; ++i) - this->CRC[i] = this->R[i]; + /* if there were any extra key bytes, zero pad to a word */ + if (i < keylen) { + for (j = 0 /* i unchanged */; i < keylen; ++i) + xtra[j++] = key[i]; + for (/* j unchanged */; j < 4; ++j) + xtra[j] = 0; + k = BYTE2WORD(xtra); + ADDKEY(k); + this->cycle(); + } - /* now diffuse */ - this->diffuse(); + /* also fold in the length of the key */ + ADDKEY(keylen); + this->cycle(); - /* now xor the copy back -- makes key loading irreversible */ - for (i = 0; i < N; ++i) - this->R[i] ^= this->CRC[i]; + /* save a copy of the register */ + for (i = 0; i < N; ++i) + this->CRC[i] = this->R[i]; + + /* now diffuse */ + this->diffuse(); + + /* now xor the copy back -- makes key loading irreversible */ + for (i = 0; i < N; ++i) + this->R[i] ^= this->CRC[i]; } -void Shannon::key(const std::vector& key) -{ - this->initState(); - this->loadKey(key); - this->genkonst(); /* in case we proceed to stream generation */ - this->saveState(); - this->nbuf = 0; +void Shannon::key(const std::vector& key) { + this->initState(); + this->loadKey(key); + this->genkonst(); /* in case we proceed to stream generation */ + this->saveState(); + this->nbuf = 0; } -void Shannon::nonce(const std::vector& nonce) -{ - this->reloadState(); - this->konst = Shannon::INITKONST; - this->loadKey(nonce); - this->genkonst(); - this->nbuf = 0; +void Shannon::nonce(const std::vector& nonce) { + this->reloadState(); + this->konst = Shannon::INITKONST; + this->loadKey(nonce); + this->genkonst(); + this->nbuf = 0; } -void Shannon::stream(std::vector& bufVec) -{ - uint8_t* endbuf; - size_t nbytes = bufVec.size(); - uint8_t* buf = bufVec.data(); - /* handle any previously buffered bytes */ - while (this->nbuf != 0 && nbytes != 0) - { - *buf++ ^= this->sbuf & 0xFF; - this->sbuf >>= 8; - this->nbuf -= 8; - --nbytes; - } +void Shannon::stream(std::vector& bufVec) { + uint8_t* endbuf; + size_t nbytes = bufVec.size(); + uint8_t* buf = bufVec.data(); + /* handle any previously buffered bytes */ + while (this->nbuf != 0 && nbytes != 0) { + *buf++ ^= this->sbuf & 0xFF; + this->sbuf >>= 8; + this->nbuf -= 8; + --nbytes; + } - /* handle whole words */ - endbuf = &buf[nbytes & ~((uint32_t)0x03)]; - while (buf < endbuf) - { - this->cycle(); - XORWORD(this->sbuf, buf); - buf += 4; - } + /* handle whole words */ + endbuf = &buf[nbytes & ~((uint32_t)0x03)]; + while (buf < endbuf) { + this->cycle(); + XORWORD(this->sbuf, buf); + buf += 4; + } - /* handle any trailing bytes */ - nbytes &= 0x03; - if (nbytes != 0) - { - this->cycle(); - this->nbuf = 32; - while (this->nbuf != 0 && nbytes != 0) - { - *buf++ ^= this->sbuf & 0xFF; - this->sbuf >>= 8; - this->nbuf -= 8; - --nbytes; - } + /* handle any trailing bytes */ + nbytes &= 0x03; + if (nbytes != 0) { + this->cycle(); + this->nbuf = 32; + while (this->nbuf != 0 && nbytes != 0) { + *buf++ ^= this->sbuf & 0xFF; + this->sbuf >>= 8; + this->nbuf -= 8; + --nbytes; } + } } -void Shannon::maconly(std::vector& bufVec) -{ - size_t nbytes = bufVec.size(); - uint8_t* buf = bufVec.data(); +void Shannon::maconly(std::vector& bufVec) { + size_t nbytes = bufVec.size(); + uint8_t* buf = bufVec.data(); - uint8_t* endbuf; + uint8_t* endbuf; - /* handle any previously buffered bytes */ - if (this->nbuf != 0) - { - while (this->nbuf != 0 && nbytes != 0) - { - this->mbuf ^= (*buf++) << (32 - this->nbuf); - this->nbuf -= 8; - --nbytes; - } - if (this->nbuf != 0) /* not a whole word yet */ - return; - /* LFSR already cycled */ - this->macfunc(this->mbuf); + /* handle any previously buffered bytes */ + if (this->nbuf != 0) { + while (this->nbuf != 0 && nbytes != 0) { + this->mbuf ^= (*buf++) << (32 - this->nbuf); + this->nbuf -= 8; + --nbytes; } + if (this->nbuf != 0) /* not a whole word yet */ + return; + /* LFSR already cycled */ + this->macfunc(this->mbuf); + } - /* handle whole words */ - endbuf = &buf[nbytes & ~((uint32_t)0x03)]; - while (buf < endbuf) - { - this->cycle(); - this->macfunc(BYTE2WORD(buf)); - buf += 4; - } + /* handle whole words */ + endbuf = &buf[nbytes & ~((uint32_t)0x03)]; + while (buf < endbuf) { + this->cycle(); + this->macfunc(BYTE2WORD(buf)); + buf += 4; + } - /* handle any trailing bytes */ - nbytes &= 0x03; - if (nbytes != 0) - { - this->cycle(); - this->mbuf = 0; - this->nbuf = 32; - while (this->nbuf != 0 && nbytes != 0) - { - this->mbuf ^= (*buf++) << (32 - this->nbuf); - this->nbuf -= 8; - --nbytes; - } + /* handle any trailing bytes */ + nbytes &= 0x03; + if (nbytes != 0) { + this->cycle(); + this->mbuf = 0; + this->nbuf = 32; + while (this->nbuf != 0 && nbytes != 0) { + this->mbuf ^= (*buf++) << (32 - this->nbuf); + this->nbuf -= 8; + --nbytes; } + } } -void Shannon::encrypt(std::vector& bufVec) -{ - size_t nbytes = bufVec.size(); - uint8_t* buf = bufVec.data(); - uint8_t* endbuf; - uint32_t t = 0; +void Shannon::encrypt(std::vector& bufVec) { + size_t nbytes = bufVec.size(); + uint8_t* buf = bufVec.data(); + uint8_t* endbuf; + uint32_t t = 0; - /* handle any previously buffered bytes */ - if (this->nbuf != 0) - { - while (this->nbuf != 0 && nbytes != 0) - { - this->mbuf ^= *buf << (32 - this->nbuf); - *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; - ++buf; - this->nbuf -= 8; - --nbytes; - } - if (this->nbuf != 0) /* not a whole word yet */ - return; - /* LFSR already cycled */ - this->macfunc(this->mbuf); + /* handle any previously buffered bytes */ + if (this->nbuf != 0) { + while (this->nbuf != 0 && nbytes != 0) { + this->mbuf ^= *buf << (32 - this->nbuf); + *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; + ++buf; + this->nbuf -= 8; + --nbytes; } + if (this->nbuf != 0) /* not a whole word yet */ + return; + /* LFSR already cycled */ + this->macfunc(this->mbuf); + } - /* handle whole words */ - endbuf = &buf[nbytes & ~((uint32_t)0x03)]; - while (buf < endbuf) - { - this->cycle(); - t = BYTE2WORD(buf); - this->macfunc(t); - t ^= this->sbuf; - WORD2BYTE(t, buf); - buf += 4; - } + /* handle whole words */ + endbuf = &buf[nbytes & ~((uint32_t)0x03)]; + while (buf < endbuf) { + this->cycle(); + t = BYTE2WORD(buf); + this->macfunc(t); + t ^= this->sbuf; + WORD2BYTE(t, buf); + buf += 4; + } - /* handle any trailing bytes */ - nbytes &= 0x03; - if (nbytes != 0) - { - this->cycle(); - this->mbuf = 0; - this->nbuf = 32; - while (this->nbuf != 0 && nbytes != 0) - { - this->mbuf ^= *buf << (32 - this->nbuf); - *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; - ++buf; - this->nbuf -= 8; - --nbytes; - } + /* handle any trailing bytes */ + nbytes &= 0x03; + if (nbytes != 0) { + this->cycle(); + this->mbuf = 0; + this->nbuf = 32; + while (this->nbuf != 0 && nbytes != 0) { + this->mbuf ^= *buf << (32 - this->nbuf); + *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; + ++buf; + this->nbuf -= 8; + --nbytes; } + } } +void Shannon::decrypt(std::vector& bufVec) { + size_t nbytes = bufVec.size(); + uint8_t* buf = bufVec.data(); + uint8_t* endbuf; + uint32_t t = 0; -void Shannon::decrypt(std::vector& bufVec) -{ - size_t nbytes = bufVec.size(); - uint8_t* buf = bufVec.data(); - uint8_t* endbuf; - uint32_t t = 0; - - /* handle any previously buffered bytes */ - if (this->nbuf != 0) - { - while (this->nbuf != 0 && nbytes != 0) - { - *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; - this->mbuf ^= *buf << (32 - this->nbuf); - ++buf; - this->nbuf -= 8; - --nbytes; - } - if (this->nbuf != 0) /* not a whole word yet */ - return; - /* LFSR already cycled */ - this->macfunc(this->mbuf); + /* handle any previously buffered bytes */ + if (this->nbuf != 0) { + while (this->nbuf != 0 && nbytes != 0) { + *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; + this->mbuf ^= *buf << (32 - this->nbuf); + ++buf; + this->nbuf -= 8; + --nbytes; } + if (this->nbuf != 0) /* not a whole word yet */ + return; + /* LFSR already cycled */ + this->macfunc(this->mbuf); + } - /* handle whole words */ - endbuf = &buf[nbytes & ~((uint32_t)0x03)]; - while (buf < endbuf) - { - this->cycle(); - t = BYTE2WORD(buf) ^ this->sbuf; - this->macfunc(t); - WORD2BYTE(t, buf); - buf += 4; - } + /* handle whole words */ + endbuf = &buf[nbytes & ~((uint32_t)0x03)]; + while (buf < endbuf) { + this->cycle(); + t = BYTE2WORD(buf) ^ this->sbuf; + this->macfunc(t); + WORD2BYTE(t, buf); + buf += 4; + } - /* handle any trailing bytes */ - nbytes &= 0x03; - if (nbytes != 0) - { - this->cycle(); - this->mbuf = 0; - this->nbuf = 32; - while (this->nbuf != 0 && nbytes != 0) - { - *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; - this->mbuf ^= *buf << (32 - this->nbuf); - ++buf; - this->nbuf -= 8; - --nbytes; - } + /* handle any trailing bytes */ + nbytes &= 0x03; + if (nbytes != 0) { + this->cycle(); + this->mbuf = 0; + this->nbuf = 32; + while (this->nbuf != 0 && nbytes != 0) { + *buf ^= (this->sbuf >> (32 - this->nbuf)) & 0xFF; + this->mbuf ^= *buf << (32 - this->nbuf); + ++buf; + this->nbuf -= 8; + --nbytes; } + } } -void Shannon::finish(std::vector& bufVec) -{ - size_t nbytes = bufVec.size(); - uint8_t* buf = bufVec.data(); - int i; +void Shannon::finish(std::vector& bufVec) { + size_t nbytes = bufVec.size(); + uint8_t* buf = bufVec.data(); + int i; - /* handle any previously buffered bytes */ - if (this->nbuf != 0) - { - /* LFSR already cycled */ - this->macfunc(this->mbuf); - } + /* handle any previously buffered bytes */ + if (this->nbuf != 0) { + /* LFSR already cycled */ + this->macfunc(this->mbuf); + } - /* perturb the MAC to mark end of input. + /* perturb the MAC to mark end of input. * Note that only the stream register is updated, not the CRC. This is an * action that can't be duplicated by passing in plaintext, hence * defeating any kind of extension attack. */ + this->cycle(); + ADDKEY(INITKONST ^ (this->nbuf << 3)); + this->nbuf = 0; + + /* now add the CRC to the stream register and diffuse it */ + for (i = 0; i < N; ++i) + this->R[i] ^= this->CRC[i]; + this->diffuse(); + + /* produce output from the stream buffer */ + while (nbytes > 0) { this->cycle(); - ADDKEY(INITKONST ^ (this->nbuf << 3)); - this->nbuf = 0; - - /* now add the CRC to the stream register and diffuse it */ - for (i = 0; i < N; ++i) - this->R[i] ^= this->CRC[i]; - this->diffuse(); - - /* produce output from the stream buffer */ - while (nbytes > 0) - { - this->cycle(); - if (nbytes >= 4) - { - WORD2BYTE(this->sbuf, buf); - nbytes -= 4; - buf += 4; - } - else - { - for (i = 0; i < nbytes; ++i) - buf[i] = Byte(this->sbuf, i); - break; - } + if (nbytes >= 4) { + WORD2BYTE(this->sbuf, buf); + nbytes -= 4; + buf += 4; + } else { + for (i = 0; i < nbytes; ++i) + buf[i] = Byte(this->sbuf, i); + break; } + } } diff --git a/components/spotify/cspot/src/ShannonConnection.cpp b/components/spotify/cspot/src/ShannonConnection.cpp index 173ebfbb..ebfe0917 100644 --- a/components/spotify/cspot/src/ShannonConnection.cpp +++ b/components/spotify/cspot/src/ShannonConnection.cpp @@ -2,16 +2,15 @@ #include // for remove_extent_t -#ifndef _WIN32 -#include -#endif - #include "BellLogger.h" // for AbstractLogger #include "Logger.h" // for CSPOT_LOG #include "Packet.h" // for Packet, cspot #include "PlainConnection.h" // for PlainConnection #include "Shannon.h" // for Shannon #include "Utils.h" // for pack, extract +#ifndef _WIN32 +#include +#endif using namespace cspot; diff --git a/components/spotify/cspot/src/SpircHandler.cpp b/components/spotify/cspot/src/SpircHandler.cpp index 814a990b..0346b25f 100644 --- a/components/spotify/cspot/src/SpircHandler.cpp +++ b/components/spotify/cspot/src/SpircHandler.cpp @@ -1,18 +1,19 @@ #include "SpircHandler.h" -#include // for uint8_t -#include // for shared_ptr, make_unique, unique_ptr -#include // for remove_extent_t -#include // for move +#include // for uint8_t +#include // for shared_ptr, make_unique, unique_ptr +#include // for remove_extent_t +#include // for move -#include "BellLogger.h" // for AbstractLogger -#include "CSpotContext.h" // for Context::ConfigState, Context (ptr only) -#include "Logger.h" // for CSPOT_LOG -#include "MercurySession.h" // for MercurySession, MercurySession::Response -#include "NanoPBHelper.h" // for pbDecode -#include "Packet.h" // for cspot -#include "PlaybackState.h" // for PlaybackState, PlaybackState::State -#include "TrackPlayer.h" // for TrackPlayer +#include "BellLogger.h" // for AbstractLogger +#include "CSpotContext.h" // for Context::ConfigState, Context (ptr only) +#include "Logger.h" // for CSPOT_LOG +#include "MercurySession.h" // for MercurySession, MercurySession::Response +#include "NanoPBHelper.h" // for pbDecode +#include "Packet.h" // for cspot +#include "PlaybackState.h" // for PlaybackState, PlaybackState::State +#include "TrackPlayer.h" // for TrackPlayer +#include "TrackQueue.h" #include "TrackReference.h" // for TrackReference #include "Utils.h" // for stringHexToBytes #include "pb_decode.h" // for pb_release @@ -20,38 +21,30 @@ using namespace cspot; -SpircHandler::SpircHandler(std::shared_ptr ctx) - : playbackState(ctx) { - - auto isAiringCallback = [this]() { - return !(isNextTrackPreloaded || isRequestedFromLoad); - }; +SpircHandler::SpircHandler(std::shared_ptr ctx) { + this->playbackState = std::make_shared(ctx); + this->trackQueue = std::make_shared(ctx, playbackState); auto EOFCallback = [this]() { - auto ref = this->playbackState.getNextTrackRef(); - - if (!isNextTrackPreloaded && !isRequestedFromLoad && ref != nullptr) { - isNextTrackPreloaded = true; - auto trackRef = TrackReference::fromTrackRef(ref); - this->trackPlayer->loadTrackFromRef(trackRef, 0, true); - } - - if (ref == nullptr) { - sendEvent(EventType::DEPLETED); - } - }; - - auto trackLoadedCallback = [this]() { - this->currentTrackInfo = this->trackPlayer->getCurrentTrackInfo(); - - if (isRequestedFromLoad) { - sendEvent(EventType::PLAYBACK_START, (int)nextTrackPosition); - setPause(false); + if (trackQueue->isFinished()) { + sendEvent(EventType::DEPLETED); } }; + auto trackLoadedCallback = [this](std::shared_ptr track) { + playbackState->setPlaybackState(PlaybackState::State::Playing); + playbackState->updatePositionMs(track->requestedPosition); + + this->notify(); + + // Send playback start event, unpause + sendEvent(EventType::PLAYBACK_START, (int) track->requestedPosition); + sendEvent(EventType::PLAY_PAUSE, false); + }; + this->ctx = ctx; - this->trackPlayer = std::make_shared(ctx, isAiringCallback, EOFCallback, trackLoadedCallback); + this->trackPlayer = std::make_shared( + ctx, trackQueue, EOFCallback, trackLoadedCallback); // Subscribe to mercury on session ready ctx->session->setConnectedHandler([this]() { this->subscribeToMercury(); }); @@ -82,105 +75,80 @@ void SpircHandler::subscribeToMercury() { subscriptionLambda); } -void SpircHandler::loadTrackFromURI(const std::string& uri) { - // {track/episode}:{gid} - bool isEpisode = uri.find("episode:") != std::string::npos; - auto gid = stringHexToBytes(uri.substr(uri.find(":") + 1)); - auto trackRef = TrackReference::fromGID(gid, isEpisode); +void SpircHandler::loadTrackFromURI(const std::string& uri) {} - isRequestedFromLoad = true; - isNextTrackPreloaded = false; +void SpircHandler::notifyAudioReachedPlayback() { + int offset = 0; - playbackState.setActive(true); + // get HEAD track + auto currentTrack = trackQueue->consumeTrack(nullptr, offset); - auto playbackRef = playbackState.getCurrentTrackRef(); + // Do not execute when meta is already updated + if (trackQueue->notifyPending) { + trackQueue->notifyPending = false; - if (playbackRef != nullptr) { - playbackState.updatePositionMs(playbackState.remoteFrame.state.position_ms); + playbackState->updatePositionMs(currentTrack->requestedPosition); - auto ref = TrackReference::fromTrackRef(playbackRef); - this->trackPlayer->loadTrackFromRef( - ref, playbackState.remoteFrame.state.position_ms, true); - playbackState.setPlaybackState(PlaybackState::State::Loading); - this->nextTrackPosition = playbackState.remoteFrame.state.position_ms; - } - - this->notify(); -} - -void SpircHandler::notifyAudioReachedPlayback() { - if (isRequestedFromLoad || isNextTrackPreloaded) { - playbackState.updatePositionMs(nextTrackPosition); - playbackState.setPlaybackState(PlaybackState::State::Playing); + // Reset position in queued track + currentTrack->requestedPosition = 0; } else { - setPause(true); - } + trackQueue->skipTrack(TrackQueue::SkipDirection::NEXT, false); + playbackState->updatePositionMs(0); - isRequestedFromLoad = false; - - if (isNextTrackPreloaded) { - isNextTrackPreloaded = false; - - playbackState.nextTrack(); - nextTrackPosition = 0; + // we moved to next track, re-acquire currentTrack again + currentTrack = trackQueue->consumeTrack(nullptr, offset); } this->notify(); - sendEvent(EventType::TRACK_INFO, this->trackPlayer->getCurrentTrackInfo()); + sendEvent(EventType::TRACK_INFO, currentTrack->trackInfo); } void SpircHandler::updatePositionMs(uint32_t position) { - playbackState.updatePositionMs(position); - notify(); + playbackState->updatePositionMs(position); + notify(); } void SpircHandler::disconnect() { - this->trackPlayer->stopTrack(); + this->trackQueue->stopTask(); + this->trackPlayer->resetState(); this->ctx->session->disconnect(); } void SpircHandler::handleFrame(std::vector& data) { - pb_release(Frame_fields, &playbackState.remoteFrame); - pbDecode(playbackState.remoteFrame, Frame_fields, data); + // Decode received spirc frame + playbackState->decodeRemoteFrame(data); - switch (playbackState.remoteFrame.typ) { + switch (playbackState->remoteFrame.typ) { case MessageType_kMessageTypeNotify: { CSPOT_LOG(debug, "Notify frame"); // Pause the playback if another player took control - if (playbackState.isActive() && - playbackState.remoteFrame.device_state.is_active) { + if (playbackState->isActive() && + playbackState->remoteFrame.device_state.is_active) { CSPOT_LOG(debug, "Another player took control, pausing playback"); - playbackState.setActive(false); - this->trackPlayer->stopTrack(); + playbackState->setActive(false); + + this->trackPlayer->stop(); sendEvent(EventType::DISC); } break; } case MessageType_kMessageTypeSeek: { - /* If next track is already downloading, we can't seek in the current one anymore. Also, - * when last track has been reached, we has to restart as we can't tell the difference */ - if ((!isNextTrackPreloaded && this->playbackState.getNextTrackRef()) || isRequestedFromLoad) { - CSPOT_LOG(debug, "Seek command while streaming current"); - playbackState.updatePositionMs(playbackState.remoteFrame.position); - trackPlayer->seekMs(playbackState.remoteFrame.position); - sendEvent(EventType::SEEK, (int)playbackState.remoteFrame.position); - } else { - CSPOT_LOG(debug, "Seek command while streaming next or before started"); - isRequestedFromLoad = true; - isNextTrackPreloaded = false; - auto ref = TrackReference::fromTrackRef(playbackState.getCurrentTrackRef()); - this->trackPlayer->loadTrackFromRef(ref, playbackState.remoteFrame.position, true); - this->nextTrackPosition = playbackState.remoteFrame.position; - } + this->trackPlayer->seekMs(playbackState->remoteFrame.position); + + playbackState->updatePositionMs(playbackState->remoteFrame.position); + notify(); + + sendEvent(EventType::SEEK, (int)playbackState->remoteFrame.position); + //sendEvent(EventType::FLUSH); break; } case MessageType_kMessageTypeVolume: - playbackState.setVolume(playbackState.remoteFrame.volume); + playbackState->setVolume(playbackState->remoteFrame.volume); this->notify(); - sendEvent(EventType::VOLUME, (int)playbackState.remoteFrame.volume); + sendEvent(EventType::VOLUME, (int)playbackState->remoteFrame.volume); break; case MessageType_kMessageTypePause: setPause(true); @@ -197,44 +165,51 @@ void SpircHandler::handleFrame(std::vector& data) { sendEvent(EventType::PREV); break; case MessageType_kMessageTypeLoad: { - CSPOT_LOG(debug, "Load frame!"); - isRequestedFromLoad = true; - isNextTrackPreloaded = false; + this->trackPlayer->start(); - playbackState.setActive(true); - playbackState.updateTracks(); + CSPOT_LOG(debug, "Load frame %d!", playbackState->remoteTracks.size()); - auto playbackRef = playbackState.getCurrentTrackRef(); - - if (playbackRef != nullptr) { - playbackState.updatePositionMs( - playbackState.remoteFrame.state.position_ms); - - auto ref = TrackReference::fromTrackRef(playbackRef); - this->trackPlayer->loadTrackFromRef( - ref, playbackState.remoteFrame.state.position_ms, true); - playbackState.setPlaybackState(PlaybackState::State::Loading); - this->nextTrackPosition = playbackState.remoteFrame.state.position_ms; + if (playbackState->remoteTracks.size() == 0) { + CSPOT_LOG(info, "No tracks in frame, stopping playback"); + break; } + playbackState->setActive(true); + + playbackState->updatePositionMs(playbackState->remoteFrame.position); + playbackState->setPlaybackState(PlaybackState::State::Playing); + + playbackState->syncWithRemote(); + + // Update track list in case we have a new one + trackQueue->updateTracks(playbackState->remoteFrame.state.position_ms, + true); + this->notify(); + + // Stop the current track, if any + trackPlayer->resetState(); break; } case MessageType_kMessageTypeReplace: { CSPOT_LOG(debug, "Got replace frame"); - playbackState.updateTracks(); + playbackState->syncWithRemote(); + + trackQueue->updateTracks(playbackState->remoteFrame.state.position_ms, + false); this->notify(); + + trackPlayer->resetState(); + sendEvent(EventType::FLUSH); break; } case MessageType_kMessageTypeShuffle: { CSPOT_LOG(debug, "Got shuffle frame"); - playbackState.setShuffle(playbackState.remoteFrame.state.shuffle); this->notify(); break; } case MessageType_kMessageTypeRepeat: { CSPOT_LOG(debug, "Got repeat frame"); - playbackState.setRepeat(playbackState.remoteFrame.state.repeat); this->notify(); break; } @@ -244,7 +219,7 @@ void SpircHandler::handleFrame(std::vector& data) { } void SpircHandler::setRemoteVolume(int volume) { - playbackState.setVolume(volume); + playbackState->setVolume(volume); notify(); } @@ -252,32 +227,34 @@ void SpircHandler::notify() { this->sendCmd(MessageType_kMessageTypeNotify); } -void SpircHandler::nextSong() { - if (playbackState.nextTrack()) { - isRequestedFromLoad = true; - isNextTrackPreloaded = false; - auto ref = TrackReference::fromTrackRef(playbackState.getCurrentTrackRef()); - this->trackPlayer->loadTrackFromRef(ref, 0, true); +void SpircHandler::skipSong(TrackQueue::SkipDirection dir) { + if (trackQueue->skipTrack(dir)) { + playbackState->setPlaybackState(PlaybackState::State::Playing); + notify(); + + // Reset track state + trackPlayer->resetState(); + + sendEvent(EventType::PLAY_PAUSE, false); } else { - sendEvent(EventType::FLUSH); - playbackState.updatePositionMs(0); - trackPlayer->stopTrack(); + playbackState->setPlaybackState(PlaybackState::State::Paused); + playbackState->updatePositionMs(0); + notify(); + + sendEvent(EventType::PLAY_PAUSE, true); } - this->nextTrackPosition = 0; + notify(); + + sendEvent(EventType::FLUSH); +} + +void SpircHandler::nextSong() { + skipSong(TrackQueue::SkipDirection::NEXT); } void SpircHandler::previousSong() { - playbackState.prevTrack(); - isRequestedFromLoad = true; - isNextTrackPreloaded = false; - - sendEvent(EventType::PREV); - auto ref = TrackReference::fromTrackRef(playbackState.getCurrentTrackRef()); - this->trackPlayer->loadTrackFromRef(ref, 0, true); - this->nextTrackPosition = 0; - - notify(); + skipSong(TrackQueue::SkipDirection::PREV); } std::shared_ptr SpircHandler::getTrackPlayer() { @@ -286,7 +263,7 @@ std::shared_ptr SpircHandler::getTrackPlayer() { void SpircHandler::sendCmd(MessageType typ) { // Serialize current player state - auto encodedFrame = playbackState.encodeCurrentFrame(typ); + auto encodedFrame = playbackState->encodeCurrentFrame(typ); auto responseLambda = [=](MercurySession::Response& res) { }; @@ -302,11 +279,11 @@ void SpircHandler::setEventHandler(EventHandler handler) { void SpircHandler::setPause(bool isPaused) { if (isPaused) { CSPOT_LOG(debug, "External pause command"); - playbackState.setPlaybackState(PlaybackState::State::Paused); + playbackState->setPlaybackState(PlaybackState::State::Paused); } else { CSPOT_LOG(debug, "External play command"); - playbackState.setPlaybackState(PlaybackState::State::Playing); + playbackState->setPlaybackState(PlaybackState::State::Playing); } notify(); sendEvent(EventType::PLAY_PAUSE, isPaused); diff --git a/components/spotify/cspot/src/TimeProvider.cpp b/components/spotify/cspot/src/TimeProvider.cpp index 5e952449..8617ef13 100644 --- a/components/spotify/cspot/src/TimeProvider.cpp +++ b/components/spotify/cspot/src/TimeProvider.cpp @@ -1,25 +1,24 @@ #include "TimeProvider.h" -#ifndef _WIN32 -#include -#endif - #include "BellLogger.h" // for AbstractLogger #include "Logger.h" // for CSPOT_LOG #include "Utils.h" // for extract, getCurrentTimestamp +#ifndef _WIN32 +#include +#endif using namespace cspot; -TimeProvider::TimeProvider() { -} +TimeProvider::TimeProvider() {} void TimeProvider::syncWithPingPacket(const std::vector& pongPacket) { - CSPOT_LOG(debug, "Time synced with spotify servers"); - // Spotify's timestamp is in seconds since unix time - convert to millis. - uint64_t remoteTimestamp = ((uint64_t) ntohl(extract(pongPacket, 0))) * 1000; - this->timestampDiff = remoteTimestamp - getCurrentTimestamp(); + CSPOT_LOG(debug, "Time synced with spotify servers"); + // Spotify's timestamp is in seconds since unix time - convert to millis. + uint64_t remoteTimestamp = + ((uint64_t)ntohl(extract(pongPacket, 0))) * 1000; + this->timestampDiff = remoteTimestamp - getCurrentTimestamp(); } unsigned long long TimeProvider::getSyncedTimestamp() { - return getCurrentTimestamp() + this->timestampDiff; + return getCurrentTimestamp() + this->timestampDiff; } \ No newline at end of file diff --git a/components/spotify/cspot/src/TrackPlayer.cpp b/components/spotify/cspot/src/TrackPlayer.cpp index 99de08d7..03155831 100644 --- a/components/spotify/cspot/src/TrackPlayer.cpp +++ b/components/spotify/cspot/src/TrackPlayer.cpp @@ -1,18 +1,26 @@ #include "TrackPlayer.h" -#include // for mutex, scoped_lock -#include // for string -#include // for remove_extent_t -#include // for vector, vector<>::value_type +#include // for mutex, scoped_lock +#include // for string +#include // for remove_extent_t +#include // for vector, vector<>::value_type #include "BellLogger.h" // for AbstractLogger #include "BellUtils.h" // for BELL_SLEEP_MS -#include "CDNTrackStream.h" // for CDNTrackStream, CDNTrackStream::TrackInfo #include "Logger.h" // for CSPOT_LOG #include "Packet.h" // for cspot -#include "TrackProvider.h" // for TrackProvider +#include "TrackQueue.h" // for CDNTrackStream, CDNTrackStream::TrackInfo #include "WrappedSemaphore.h" // for WrappedSemaphore +#ifdef BELL_VORBIS_FLOAT +#define VORBIS_SEEK(file, position) (ov_time_seek(file, (double)position / 1000)) +#define VORBIS_READ(file, buffer, bufferSize, section) (ov_read(file, buffer, bufferSize, 0, 2, 1, section)) +#else +#define VORBIS_SEEK(file, position) (ov_time_seek(file, position)) +#define VORBIS_READ(file, buffer, bufferSize, section) \ + (ov_read(file, buffer, bufferSize, section)) +#endif + namespace cspot { struct Context; struct TrackReference; @@ -38,13 +46,14 @@ static long vorbisTellCb(TrackPlayer* self) { return self->_vorbisTell(); } -TrackPlayer::TrackPlayer(std::shared_ptr ctx, isAiringCallback isAiring, EOFCallback eof, TrackLoadedCallback trackLoaded) - : bell::Task("cspot_player", 48 * 1024, 5, 1) { +TrackPlayer::TrackPlayer(std::shared_ptr ctx, + std::shared_ptr trackQueue, + EOFCallback eof, TrackLoadedCallback trackLoaded) + : bell::Task("cspot_player", 32 * 1024, 5, 1) { this->ctx = ctx; - this->isAiring = isAiring; this->eofCallback = eof; this->trackLoaded = trackLoaded; - this->trackProvider = std::make_shared(ctx); + this->trackQueue = trackQueue; this->playbackSemaphore = std::make_unique(5); // Initialize vorbis callbacks @@ -55,9 +64,6 @@ TrackPlayer::TrackPlayer(std::shared_ptr ctx, isAiringCallback i (decltype(ov_callbacks::close_func))&vorbisCloseCb, (decltype(ov_callbacks::tell_func))&vorbisTellCb, }; - isRunning = true; - - startTask(); } TrackPlayer::~TrackPlayer() { @@ -65,123 +71,192 @@ TrackPlayer::~TrackPlayer() { std::scoped_lock lock(runningMutex); } -void TrackPlayer::loadTrackFromRef(TrackReference& ref, size_t positionMs, - bool startAutomatically) { - this->playbackPosition = positionMs; - this->autoStart = startAutomatically; - - auto nextTrack = trackProvider->loadFromTrackRef(ref); - - stopTrack(); - this->sequence++; - this->currentTrackStream = nextTrack; - this->playbackSemaphore->give(); +void TrackPlayer::start() { + if (!isRunning) { + isRunning = true; + startTask(); + } } -void TrackPlayer::stopTrack() { +void TrackPlayer::stop() { + isRunning = false; + resetState(); + std::scoped_lock lock(runningMutex); +} + +void TrackPlayer::resetState() { + // Mark for reset + this->pendingReset = true; this->currentSongPlaying = false; - std::scoped_lock lock(playbackMutex); + + std::scoped_lock lock(dataOutMutex); + + CSPOT_LOG(info, "Resetting state"); } void TrackPlayer::seekMs(size_t ms) { - std::scoped_lock lock(seekMutex); -#ifdef BELL_VORBIS_FLOAT - ov_time_seek(&vorbisFile, (double)ms / 1000); -#else - ov_time_seek(&vorbisFile, ms); -#endif + if (inFuture) { + // We're in the middle of the next track, so we need to reset the player in order to seek + resetState(); + } + + CSPOT_LOG(info, "Seeking..."); + this->pendingSeekPositionMs = ms; } void TrackPlayer::runTask() { std::scoped_lock lock(runningMutex); + std::shared_ptr track, newTrack = nullptr; + + int trackOffset = 0; + bool eof = false; + bool endOfQueueReached = false; + while (isRunning) { - this->playbackSemaphore->twait(100); - - if (this->currentTrackStream == nullptr) { + // Ensure we even have any tracks to play + if (!this->trackQueue->hasTracks() || + (endOfQueueReached && trackQueue->isFinished())) { + this->trackQueue->playableSemaphore->twait(300); continue; } - CSPOT_LOG(info, "Player received a track, waiting for it to be ready..."); - - // when track changed many times and very quickly, we are stuck on never-given semaphore - while (this->currentTrackStream->trackReady->twait(250)); - CSPOT_LOG(info, "Got track"); + // Last track was interrupted, reset to default + if (pendingReset) { + track = nullptr; + pendingReset = false; + inFuture = false; + } - if (this->currentTrackStream->status == CDNTrackStream::Status::FAILED) { - CSPOT_LOG(error, "Track failed to load, skipping it"); - this->currentTrackStream = nullptr; - this->eofCallback(); + endOfQueueReached = false; + + // Wait 800ms. If next reset is requested in meantime, restart the queue. + // Gets rid of excess actions during rapid queueing + BELL_SLEEP_MS(50); + + if (pendingReset) { continue; } - this->currentSongPlaying = true; + newTrack = trackQueue->consumeTrack(track, trackOffset); - this->trackLoaded(); + if (newTrack == nullptr) { + if (trackOffset == -1) { + // Reset required + track = nullptr; + } - this->playbackMutex.lock(); - - int32_t r = ov_open_callbacks(this, &vorbisFile, NULL, 0, vorbisCallbacks); - - if (playbackPosition > 0) { -#ifdef BELL_VORBIS_FLOAT - ov_time_seek(&vorbisFile, (double)playbackPosition / 1000); -#else - ov_time_seek(&vorbisFile, playbackPosition); -#endif + BELL_SLEEP_MS(100); + continue; } - bool eof = false; + track = newTrack; - while (!eof && currentSongPlaying) { - seekMutex.lock(); -#ifdef BELL_VORBIS_FLOAT - long ret = ov_read(&vorbisFile, (char*)&pcmBuffer[0], pcmBuffer.size(), - 0, 2, 1, ¤tSection); -#else - long ret = ov_read(&vorbisFile, (char*)&pcmBuffer[0], pcmBuffer.size(), - ¤tSection); -#endif - seekMutex.unlock(); - if (ret == 0) { - CSPOT_LOG(info, "EOF"); - // and done :) - eof = true; - } else if (ret < 0) { - CSPOT_LOG(error, "An error has occured in the stream %d", ret); - currentSongPlaying = false; - } else { + inFuture = trackOffset > 0; - if (this->dataCallback != nullptr) { - auto toWrite = ret; + if (track->state != QueuedTrack::State::READY) { + track->loadedSemaphore->twait(5000); - while (!eof && currentSongPlaying && toWrite > 0) { - auto written = - dataCallback(pcmBuffer.data() + (ret - toWrite), toWrite, - this->currentTrackStream->trackInfo.trackId, this->sequence); - if (written == 0) { - BELL_SLEEP_MS(50); + if (track->state != QueuedTrack::State::READY) { + CSPOT_LOG(error, "Track failed to load, skipping it"); + this->eofCallback(); + continue; + } + } + + CSPOT_LOG(info, "Got track ID=%s", track->identifier.c_str()); + + currentSongPlaying = true; + + { + std::scoped_lock lock(playbackMutex); + + currentTrackStream = track->getAudioFile(); + + // Open the stream + currentTrackStream->openStream(); + + if (pendingReset || !currentSongPlaying) { + continue; + } + + if (trackOffset == 0 && pendingSeekPositionMs == 0) { + this->trackLoaded(track); + } + + int32_t r = + ov_open_callbacks(this, &vorbisFile, NULL, 0, vorbisCallbacks); + + if (pendingSeekPositionMs > 0) { + track->requestedPosition = pendingSeekPositionMs; + } + + if (track->requestedPosition > 0) { + VORBIS_SEEK(&vorbisFile, track->requestedPosition); + } + + eof = false; + + CSPOT_LOG(info, "Playing"); + + while (!eof && currentSongPlaying) { + // Execute seek if needed + if (pendingSeekPositionMs > 0) { + uint32_t seekPosition = pendingSeekPositionMs; + + // Reset the pending seek position + pendingSeekPositionMs = 0; + + // Seek to the new position + VORBIS_SEEK(&vorbisFile, seekPosition); + } + + long ret = VORBIS_READ(&vorbisFile, (char*)&pcmBuffer[0], + pcmBuffer.size(), ¤tSection); + + if (ret == 0) { + CSPOT_LOG(info, "EOF"); + // and done :) + eof = true; + } else if (ret < 0) { + CSPOT_LOG(error, "An error has occured in the stream %d", ret); + currentSongPlaying = false; + } else { + if (this->dataCallback != nullptr) { + auto toWrite = ret; + + while (!eof && currentSongPlaying && !pendingReset && toWrite > 0) { + int written = 0; + { + std::scoped_lock dataOutLock(dataOutMutex); + // If reset happened during playback, return + if (!currentSongPlaying || pendingReset) + break; + + written = + dataCallback(pcmBuffer.data() + (ret - toWrite), toWrite, track->identifier); + } + if (written == 0) { + BELL_SLEEP_MS(50); + } + toWrite -= written; } - toWrite -= written; } } } - } - ov_clear(&vorbisFile); + ov_clear(&vorbisFile); - // With very large buffers, track N+1 can be downloaded while N has not aired yet and - // if we continue, the currentTrackStream will be emptied, causing a crash in - // notifyAudioReachedPlayback when it will look for trackInfo. A busy loop is never - // ideal, but this low impact, infrequent and more simple than yet another semaphore - while (currentSongPlaying && !isAiring()) { - BELL_SLEEP_MS(100); - } + CSPOT_LOG(info, "Playing done"); - // always move back to LOADING (ensure proper seeking after last track has been loaded) - this->currentTrackStream.reset(); - this->playbackMutex.unlock(); + // always move back to LOADING (ensure proper seeking after last track has been loaded) + currentTrackStream = nullptr; + } if (eof) { + if (trackQueue->isFinished()) { + endOfQueueReached = true; + } + this->eofCallback(); } } @@ -226,10 +301,6 @@ long TrackPlayer::_vorbisTell() { return this->currentTrackStream->getPosition(); } -CDNTrackStream::TrackInfo TrackPlayer::getCurrentTrackInfo() { - return this->currentTrackStream->trackInfo; -} - void TrackPlayer::setDataCallback(DataCallback callback) { this->dataCallback = callback; } diff --git a/components/spotify/cspot/src/Utils.cpp b/components/spotify/cspot/src/Utils.cpp index 6983e3ae..329f358f 100644 --- a/components/spotify/cspot/src/Utils.cpp +++ b/components/spotify/cspot/src/Utils.cpp @@ -8,7 +8,7 @@ #include // for enable_if<>::type #include #ifndef _WIN32 -#include +#include #endif unsigned long long getCurrentTimestamp() {