Merge branch 'master-v4.3' of https://github.com/wizmo2/squeezelite-esp32 into led_visu-v4.3

This commit is contained in:
Wizmo2
2023-04-23 01:30:15 -04:00
61 changed files with 712 additions and 490 deletions

View File

@@ -66,7 +66,7 @@ static void squeezelite_thread(void *arg){
cmd_send_messaging("cfg-audio-tmpl",ret > 1 ? MESSAGING_ERROR : MESSAGING_WARNING,"squeezelite exited with error code %d\n", ret); cmd_send_messaging("cfg-audio-tmpl",ret > 1 ? MESSAGING_ERROR : MESSAGING_WARNING,"squeezelite exited with error code %d\n", ret);
if (ret == 1) { if (ret <= 1) {
int wait = 60; int wait = 60;
wait_for_commit(); wait_for_commit();
cmd_send_messaging("cfg-audio-tmpl",MESSAGING_ERROR,"Rebooting in %d sec\n", wait); cmd_send_messaging("cfg-audio-tmpl",MESSAGING_ERROR,"Rebooting in %d sec\n", wait);

View File

@@ -16,7 +16,10 @@
#include <stdarg.h> #include <stdarg.h>
#include <ApResolve.h> #include <ApResolve.h>
#include "BellTask.h"
#include "MDNSService.h" #include "MDNSService.h"
#include "TrackPlayer.h"
#include "CSpotContext.h"
#include "SpircHandler.h" #include "SpircHandler.h"
#include "LoginBlob.h" #include "LoginBlob.h"
#include "CentralAudioBuffer.h" #include "CentralAudioBuffer.h"
@@ -39,13 +42,13 @@ class chunkManager : public bell::Task {
public: public:
std::atomic<bool> isRunning = true; std::atomic<bool> isRunning = true;
std::atomic<bool> isPaused = true; std::atomic<bool> isPaused = true;
std::atomic<bool> discard = true; chunkManager(std::function<void()> trackHandler, std::function<void(const uint8_t*, size_t)> dataHandler);
chunkManager(std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer, std::function<void()> trackHandler, size_t writePCM(uint8_t* data, size_t bytes, std::string_view trackId, size_t sequence);
std::function<void(const uint8_t*, size_t)> dataHandler); void flush();
void teardown(); void teardown();
private: private:
std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer; std::unique_ptr<bell::CentralAudioBuffer> centralAudioBuffer;
std::function<void()> trackHandler; std::function<void()> trackHandler;
std::function<void(const uint8_t*, size_t)> dataHandler; std::function<void(const uint8_t*, size_t)> dataHandler;
std::mutex runningMutex; std::mutex runningMutex;
@@ -53,20 +56,27 @@ private:
void runTask() override; void runTask() override;
}; };
chunkManager::chunkManager(std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer, chunkManager::chunkManager(std::function<void()> trackHandler, std::function<void(const uint8_t*, size_t)> dataHandler)
std::function<void()> trackHandler, std::function<void(const uint8_t*, size_t)> dataHandler)
: bell::Task("chunker", 4 * 1024, 0, 0) { : bell::Task("chunker", 4 * 1024, 0, 0) {
this->centralAudioBuffer = centralAudioBuffer; this->centralAudioBuffer = std::make_unique<bell::CentralAudioBuffer>(32);
this->trackHandler = trackHandler; this->trackHandler = trackHandler;
this->dataHandler = dataHandler; this->dataHandler = dataHandler;
startTask(); 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() { void chunkManager::teardown() {
isRunning = false; isRunning = false;
std::scoped_lock lock(runningMutex); std::scoped_lock lock(runningMutex);
} }
void chunkManager::flush() {
centralAudioBuffer->clearBuffer();
}
void chunkManager::runTask() { void chunkManager::runTask() {
std::scoped_lock lock(runningMutex); std::scoped_lock lock(runningMutex);
size_t lastHash = 0; size_t lastHash = 0;
@@ -89,11 +99,10 @@ void chunkManager::runTask() {
if (lastHash != chunk->trackHash) { if (lastHash != chunk->trackHash) {
CSPOT_LOG(info, "hash update %x => %x", lastHash, chunk->trackHash); CSPOT_LOG(info, "hash update %x => %x", lastHash, chunk->trackHash);
lastHash = chunk->trackHash; lastHash = chunk->trackHash;
discard = false;
trackHandler(); trackHandler();
} }
if (!discard) dataHandler(chunk->pcmData, chunk->pcmSize); dataHandler(chunk->pcmData, chunk->pcmSize);
} }
} }
@@ -105,7 +114,6 @@ class cspotPlayer : public bell::Task {
private: private:
std::string name; std::string name;
bell::WrappedSemaphore clientConnected; bell::WrappedSemaphore clientConnected;
std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer;
int startOffset, volume = 0, bitrate = 160; int startOffset, volume = 0, bitrate = 160;
httpd_handle_t serverHandle; httpd_handle_t serverHandle;
@@ -225,8 +233,7 @@ esp_err_t cspotPlayer::handlePOST(httpd_req_t *request) {
void cspotPlayer::eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event) { void cspotPlayer::eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event) {
switch (event->eventType) { switch (event->eventType) {
case cspot::SpircHandler::EventType::PLAYBACK_START: { case cspot::SpircHandler::EventType::PLAYBACK_START: {
chunker->discard = true; chunker->flush();
centralAudioBuffer->clearBuffer();
// we are not playing anymore // we are not playing anymore
trackStatus = TRACK_INIT; trackStatus = TRACK_INIT;
@@ -257,17 +264,17 @@ void cspotPlayer::eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event
case cspot::SpircHandler::EventType::PREV: case cspot::SpircHandler::EventType::PREV:
case cspot::SpircHandler::EventType::FLUSH: { case cspot::SpircHandler::EventType::FLUSH: {
// FLUSH is sent when there is no next, just clean everything // FLUSH is sent when there is no next, just clean everything
centralAudioBuffer->clearBuffer(); chunker->flush();
cmdHandler(CSPOT_FLUSH); cmdHandler(CSPOT_FLUSH);
break; break;
} }
case cspot::SpircHandler::EventType::DISC: case cspot::SpircHandler::EventType::DISC:
centralAudioBuffer->clearBuffer(); chunker->flush();
cmdHandler(CSPOT_DISC); cmdHandler(CSPOT_DISC);
chunker->teardown(); chunker->teardown();
break; break;
case cspot::SpircHandler::EventType::SEEK: { case cspot::SpircHandler::EventType::SEEK: {
centralAudioBuffer->clearBuffer(); chunker->flush();
cmdHandler(CSPOT_SEEK, std::get<int>(event->data)); cmdHandler(CSPOT_SEEK, std::get<int>(event->data));
break; break;
} }
@@ -372,7 +379,6 @@ void cspotPlayer::runTask() {
CSPOT_LOG(info, "Spotify client connected for %s", name.c_str()); CSPOT_LOG(info, "Spotify client connected for %s", name.c_str());
centralAudioBuffer = std::make_shared<bell::CentralAudioBuffer>(32);
auto ctx = cspot::Context::createFromBlob(blob); auto ctx = cspot::Context::createFromBlob(blob);
if (bitrate == 320) ctx->config.audioFormat = AudioFormat_OGG_VORBIS_320; if (bitrate == 320) ctx->config.audioFormat = AudioFormat_OGG_VORBIS_320;
@@ -386,10 +392,19 @@ void cspotPlayer::runTask() {
if (token.size() > 0) { if (token.size() > 0) {
spirc = std::make_unique<cspot::SpircHandler>(ctx); spirc = std::make_unique<cspot::SpircHandler>(ctx);
// Create a player, pass the track handler
chunker = std::make_unique<chunkManager>(
[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 // set call back to calculate a hash on trackId
spirc->getTrackPlayer()->setDataCallback( spirc->getTrackPlayer()->setDataCallback(
[this](uint8_t* data, size_t bytes, std::string_view trackId, size_t sequence) { [this](uint8_t* data, size_t bytes, std::string_view trackId, size_t sequence) {
return centralAudioBuffer->writePCM(data, bytes, sequence); return chunker->writePCM(data, bytes, trackId, sequence);
}); });
// set event (PLAY, VOLUME...) handler // set event (PLAY, VOLUME...) handler
@@ -401,15 +416,6 @@ void cspotPlayer::runTask() {
// Start handling mercury messages // Start handling mercury messages
ctx->session->startTask(); ctx->session->startTask();
// Create a player, pass the tack handler
chunker = std::make_unique<chunkManager>(centralAudioBuffer,
[this](void) {
return trackHandler();
},
[this](const uint8_t* data, size_t bytes) {
return dataHandler(data, bytes);
});
// set volume at connection // set volume at connection
cmdHandler(CSPOT_VOLUME, volume); cmdHandler(CSPOT_VOLUME, volume);
@@ -447,7 +453,6 @@ void cspotPlayer::runTask() {
} }
// we want to release memory ASAP and for sure // we want to release memory ASAP and for sure
centralAudioBuffer.reset();
ctx.reset(); ctx.reset();
token.clear(); token.clear();

View File

@@ -71,6 +71,7 @@ class CentralAudioBuffer {
void clearBuffer() { void clearBuffer() {
std::scoped_lock lock(this->dataAccessMutex); std::scoped_lock lock(this->dataAccessMutex);
//size_t exceptSize = currentSampleRate + (sizeof(AudioChunk) - (currentSampleRate % sizeof(AudioChunk))); //size_t exceptSize = currentSampleRate + (sizeof(AudioChunk) - (currentSampleRate % sizeof(AudioChunk)));
hasChunk = false;
audioBuffer->emptyBuffer(); audioBuffer->emptyBuffer();
} }

View File

@@ -1,12 +1,12 @@
#pragma once #pragma once
#include <functional> #include <functional> // for function
#include <memory> #include <memory> // for shared_ptr
#include <string> // for string
#include "CSpotContext.h"
#include "Utils.h"
namespace cspot { namespace cspot {
struct Context;
class AccessKeyFetcher { class AccessKeyFetcher {
public: public:
AccessKeyFetcher(std::shared_ptr<cspot::Context> ctx); AccessKeyFetcher(std::shared_ptr<cspot::Context> ctx);

View File

@@ -1,13 +1,9 @@
#pragma once #pragma once
#include <memory> #include <string> // for string
#include <string>
#include "HTTPClient.h"
#ifdef BELL_ONLY_CJSON #ifdef BELL_ONLY_CJSON
#include "cJSON.h" #include "cJSON.h"
#else #else
#include "nlohmann/json.hpp"
#endif #endif
namespace cspot { namespace cspot {

View File

@@ -1,20 +1,14 @@
#pragma once #pragma once
#include <algorithm> #include <cstdint> // for uint8_t
#include <climits> #include <memory> // for unique_ptr
#include <functional> #include <string> // for string
#include <memory> #include <vector> // for vector
#include <random>
#include <vector>
#include "Crypto.h" #include "Crypto.h" // for Crypto
#include "Logger.h" #include "protobuf/authentication.pb.h" // for ClientResponseEncrypted
#include "NanoPBHelper.h" #include "protobuf/keyexchange.pb.h" // for APResponseMessage, ClientHello
#include "Utils.h"
#include "protobuf/authentication.pb.h"
#include "protobuf/keyexchange.pb.h"
namespace cspot { namespace cspot {
class AuthChallenges { class AuthChallenges {

View File

@@ -1,16 +1,20 @@
#pragma once #pragma once
#include <cstddef> #include <cstddef> // for size_t
#include <memory> #include <cstdint> // for uint8_t
#include "Crypto.h" #include <memory> // for shared_ptr, unique_ptr
#include "WrappedSemaphore.h" #include <string> // for string
#include <vector> // for vector
#include "Logger.h" #include "Crypto.h" // for Crypto
#include "Utils.h" #include "HTTPClient.h" // for HTTPClient
#include "CSpotContext.h"
#include "AccessKeyFetcher.h" namespace bell {
class WrappedSemaphore;
} // namespace bell
namespace cspot { namespace cspot {
class AccessKeyFetcher;
class CDNTrackStream { class CDNTrackStream {

View File

@@ -5,6 +5,7 @@
#include "MercurySession.h" #include "MercurySession.h"
#include "TimeProvider.h" #include "TimeProvider.h"
#include "protobuf/metadata.pb.h" #include "protobuf/metadata.pb.h"
#include "LoginBlob.h"
namespace cspot { namespace cspot {
struct Context { struct Context {

View File

@@ -1,17 +1,12 @@
#pragma once #pragma once
#include <iostream> #include <cstdint> // for uint8_t, uint32_t
#include <map> #include <map> // for map
#include <memory> #include <memory> // for unique_ptr
#ifndef BELL_ONLY_CJSON #include <string> // for string
#include <nlohmann/json.hpp> #include <vector> // for vector
#endif
#include <vector>
#include "ConstantParameters.h" #include "Crypto.h" // for CryptoMbedTLS, Crypto
#include "Crypto.h"
#include "protobuf/authentication.pb.h"
namespace cspot { namespace cspot {
class LoginBlob { class LoginBlob {

View File

@@ -1,22 +1,23 @@
#pragma once #pragma once
#include <atomic> #include <atomic> // for atomic
#include <functional> #include <cstdint> // for uint8_t, uint64_t, uint32_t
#include <memory> #include <functional> // for function
#include <string> #include <memory> // for shared_ptr
#include <unordered_map> #include <mutex> // for mutex
#include <vector> #include <string> // for string
#include "BellTask.h" #include <unordered_map> // for unordered_map
#include "Logger.h" #include <vector> // for vector
#include "NanoPBHelper.h"
#include "Packet.h" #include "BellTask.h" // for Task
#include "Queue.h" #include "Packet.h" // for Packet
#include "Session.h" #include "Queue.h" // for Queue
#include "TimeProvider.h" #include "Session.h" // for Session
#include "Utils.h" #include "protobuf/mercury.pb.h" // for Header
#include "protobuf/mercury.pb.h"
namespace cspot { namespace cspot {
class TimeProvider;
class MercurySession : public bell::Task, public cspot::Session { class MercurySession : public bell::Task, public cspot::Session {
public: public:
MercurySession(std::shared_ptr<cspot::TimeProvider> timeProvider); MercurySession(std::shared_ptr<cspot::TimeProvider> timeProvider);

View File

@@ -3,19 +3,15 @@
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include "win32shim.h" #include "win32shim.h"
#else #else
#include <netdb.h> #include <unistd.h> // for size_t
#include <unistd.h>
#include "sys/socket.h"
#include <netinet/in.h>
#endif #endif
#include <cstdint> #include <cstdint> // for uint8_t
#include <functional> #include <functional> // for function
#include <string> #include <string> // for string
#include <vector> #include <vector> // for vector
#include "Packet.h"
#include "Utils.h"
typedef std::function<bool()> timeoutCallback; typedef std::function<bool()> timeoutCallback;

View File

@@ -1,18 +1,14 @@
#pragma once #pragma once
#include <NanoPBHelper.h> #include <stdint.h> // for uint8_t, uint32_t
#include <memory> #include <memory> // for shared_ptr
#include <string> #include <string> // for string
#include <vector> #include <vector> // for vector
#include "CSpotContext.h"
#include "ConstantParameters.h"
#include "CspotAssert.h"
#include "TimeProvider.h"
#include "Utils.h"
#include "protobuf/spirc.pb.h" #include "protobuf/spirc.pb.h" // for Frame, TrackRef, CapabilityType, Mess...
namespace cspot { namespace cspot {
struct Context;
class PlaybackState { class PlaybackState {
private: private:

View File

@@ -1,20 +1,16 @@
#pragma once #pragma once
#include <algorithm> #include <stdint.h> // for uint8_t
#include <functional> #include <memory> // for shared_ptr, unique_ptr
#include <memory> #include <string> // for string
#include <vector> #include <vector> // for vector
#include "ApResolve.h" namespace cspot {
#include "AuthChallenges.h" class AuthChallenges;
#include "ConstantParameters.h" class LoginBlob;
#include "Logger.h" class PlainConnection;
#include "LoginBlob.h" class ShannonConnection;
#include "Packet.h" } // namespace cspot
#include "PlainConnection.h"
#include "ShannonConnection.h"
#include "Utils.h"
#include "protobuf/mercury.pb.h"
#define LOGIN_REQUEST_COMMAND 0xAB #define LOGIN_REQUEST_COMMAND 0xAB
#define AUTH_SUCCESSFUL_COMMAND 0xAC #define AUTH_SUCCESSFUL_COMMAND 0xAC

View File

@@ -1,8 +1,9 @@
#ifndef SHANNON_H #ifndef SHANNON_H
#define SHANNON_H #define SHANNON_H
#include <cstdint> #include <cstdint> // for uint32_t, uint8_t
#include <vector> #include <vector> // for vector
class Shannon class Shannon
{ {
public: public:

View File

@@ -1,18 +1,18 @@
#ifndef SHANNONCONNECTION_H #ifndef SHANNONCONNECTION_H
#define SHANNONCONNECTION_H #define SHANNONCONNECTION_H
#include <sys/types.h> #include <cstdint> // for uint8_t, uint32_t
#include <cstdint> #include <memory> // for shared_ptr, unique_ptr
#include <memory> #include <mutex> // for mutex
#include <string> #include <vector> // for vector
#include <vector>
#include "Packet.h" #include "Packet.h" // for Packet
#include "PlainConnection.h"
#include "Shannon.h" class Shannon;
#include <mutex> namespace cspot {
#include "Utils.h"
#include "Logger.h" class PlainConnection;
} // namespace cspot
#define MAC_SIZE 4 #define MAC_SIZE 4
namespace cspot { namespace cspot {

View File

@@ -1,16 +1,20 @@
#pragma once #pragma once
#include <memory> #include <stdint.h> // for uint32_t, uint8_t
#include "BellTask.h" #include <functional> // for function
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <variant> // for variant
#include <vector> // for vector
#include "CDNTrackStream.h" #include "CDNTrackStream.h" // for CDNTrackStream, CDNTrackStream::Track...
#include "CSpotContext.h" #include "PlaybackState.h" // for PlaybackState
#include "PlaybackState.h" #include "protobuf/spirc.pb.h" // for MessageType
#include "TrackPlayer.h"
#include "TrackProvider.h"
#include "protobuf/spirc.pb.h"
namespace cspot { namespace cspot {
class TrackPlayer;
struct Context;
class SpircHandler { class SpircHandler {
public: public:
SpircHandler(std::shared_ptr<cspot::Context> ctx); SpircHandler(std::shared_ptr<cspot::Context> ctx);

View File

@@ -1,9 +1,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h> // for uint8_t
#include <vector> #include <vector> // for vector
#include "Utils.h"
namespace cspot { namespace cspot {
class TimeProvider { class TimeProvider {

View File

@@ -1,22 +1,31 @@
#pragma once #pragma once
#include <functional> #include <atomic> // for atomic
#include <memory> #include <cstdint> // for uint8_t, int64_t
#include <mutex> #include <ctime> // for size_t, time
#include <atomic> #include <functional> // for function
#include <BellUtils.h> #include <memory> // for shared_ptr, unique_ptr
#include <WrappedSemaphore.h> #include <mutex> // for mutex
#include "CDNTrackStream.h" #include <string_view> // for string_view
#include "CSpotContext.h" #include <vector> // for vector
#include "TrackProvider.h"
#include "TrackReference.h" #include "BellTask.h" // for Task
#include "CDNTrackStream.h" // for CDNTrackStream, CDNTrackStream::TrackInfo
namespace bell {
class WrappedSemaphore;
} // namespace bell
#ifdef BELL_VORBIS_FLOAT #ifdef BELL_VORBIS_FLOAT
#include "vorbis/vorbisfile.h" #include "vorbis/vorbisfile.h"
#else #else
#include "ivorbisfile.h" #include "ivorbisfile.h" // for OggVorbis_File, ov_callbacks
#endif #endif
namespace cspot { namespace cspot {
class TrackProvider;
struct Context;
struct TrackReference;
class TrackPlayer : bell::Task { class TrackPlayer : bell::Task {
public: public:
typedef std::function<void()> TrackLoadedCallback; typedef std::function<void()> TrackLoadedCallback;

View File

@@ -1,15 +1,18 @@
#pragma once #pragma once
#include <memory> #include <stdint.h> // for uint8_t
#include <memory> // for shared_ptr, unique_ptr, weak_ptr
#include <vector> // for vector
#include "AccessKeyFetcher.h" #include "MercurySession.h" // for MercurySession
#include "CDNTrackStream.h" #include "TrackReference.h" // for TrackReference
#include "CSpotContext.h" #include "protobuf/metadata.pb.h" // for Episode, Restriction, Track
#include "TrackReference.h"
#include "protobuf/metadata.pb.h"
#include "protobuf/spirc.pb.h"
namespace cspot { namespace cspot {
class AccessKeyFetcher;
class CDNTrackStream;
struct Context;
class TrackProvider { class TrackProvider {
public: public:
TrackProvider(std::shared_ptr<cspot::Context> ctx); TrackProvider(std::shared_ptr<cspot::Context> ctx);
@@ -23,11 +26,13 @@ class TrackProvider {
std::unique_ptr<cspot::CDNTrackStream> cdnStream; std::unique_ptr<cspot::CDNTrackStream> cdnStream;
Track trackInfo; Track trackInfo;
Episode episodeInfo;
std::weak_ptr<CDNTrackStream> currentTrackReference; std::weak_ptr<CDNTrackStream> currentTrackReference;
TrackReference trackIdInfo; TrackReference trackIdInfo;
void queryMetadata(); void queryMetadata();
void onMetadataResponse(MercurySession::Response& res); void onMetadataResponse(MercurySession::Response& res);
bool doRestrictionsApply(Restriction* restrictions, int count);
void fetchFile(const std::vector<uint8_t>& fileId, void fetchFile(const std::vector<uint8_t>& fileId,
const std::vector<uint8_t>& trackId); const std::vector<uint8_t>& trackId);
bool canPlayTrack(int index); bool canPlayTrack(int index);

View File

@@ -28,12 +28,11 @@ struct TrackReference {
// Episode GID is being fetched via base62 encoded URI // Episode GID is being fetched via base62 encoded URI
auto uri = std::string(ref->uri); auto uri = std::string(ref->uri);
auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size()); auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size());
trackRef.gid = {0}; trackRef.gid = {0};
std::string_view alphabet(base62Alphabet); std::string_view alphabet(base62Alphabet);
for (int x = 0; x < uri.size(); x++) { for (int x = 0; x < idString.size(); x++) {
size_t d = alphabet.find(uri[x]); size_t d = alphabet.find(idString[x]);
trackRef.gid = bigNumMultiply(trackRef.gid, 62); trackRef.gid = bigNumMultiply(trackRef.gid, 62);
trackRef.gid = bigNumAdd(trackRef.gid, d); trackRef.gid = bigNumAdd(trackRef.gid, d);
} }

View File

@@ -1,27 +1,20 @@
#ifndef UTILS_H #ifndef UTILS_H
#define UTILS_H #define UTILS_H
#include <vector> #include <cstdio> // for snprintf, size_t
#include <vector> // for vector
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include "win32shim.h" #include "win32shim.h"
#else #else
#include <unistd.h>
#include "sys/socket.h"
#include <netdb.h>
#include <netinet/in.h>
#endif #endif
#include <cstdint> #include <cstdint> // for uint8_t, uint64_t
#include <cstring> #include <cstring> // for memcpy
#include <memory> #include <memory> // for unique_ptr
#include <chrono> #include <stdexcept> // for runtime_error
#include <string> #include <string> // for string
#include <sstream>
#include <iostream>
#include <iomanip>
#include <memory>
#include <string>
#include <stdexcept>
#define HMAC_SHA1_BLOCKSIZE 64 #define HMAC_SHA1_BLOCKSIZE 64

View File

@@ -12,7 +12,8 @@ Album.name type: FT_POINTER
Episode.gid type: FT_POINTER Episode.gid type: FT_POINTER
Episode.name type: FT_POINTER Episode.name type: FT_POINTER
ImageGroup.image type: FT_POINTER ImageGroup.image type: FT_POINTER
Episode.audio type: FT_POINTER Episode.file type: FT_POINTER
Episode.restriction type: FT_POINTER
Episode.covers type: FT_POINTER Episode.covers type: FT_POINTER
Restriction.countries_allowed type: FT_POINTER Restriction.countries_allowed type: FT_POINTER
Restriction.countries_forbidden type: FT_POINTER Restriction.countries_forbidden type: FT_POINTER

View File

@@ -44,7 +44,8 @@ message Episode {
optional bytes gid = 1; optional bytes gid = 1;
optional string name = 2; optional string name = 2;
optional sint32 duration = 7; optional sint32 duration = 7;
repeated AudioFile audio = 12; repeated AudioFile file = 12;
repeated Restriction restriction = 0x4B;
optional ImageGroup covers = 0x44; optional ImageGroup covers = 0x44;
} }

View File

@@ -1,7 +1,24 @@
#include "AccessKeyFetcher.h" #include "AccessKeyFetcher.h"
#include <cstring>
#include "Logger.h" #include <cstring> // for strrchr
#include "Utils.h" #include <initializer_list> // for initializer_list
#include <map> // for operator!=, operator==
#include <type_traits> // for remove_extent_t
#include <vector> // 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
#ifdef BELL_ONLY_CJSON
#include "cJSON.h"
#else
#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json
#include "nlohmann/json_fwd.hpp" // for json
#endif
using namespace cspot; using namespace cspot;
@@ -38,12 +55,15 @@ void AccessKeyFetcher::getAccessKey(AccessKeyFetcher::Callback callback) {
ctx->session->execute( ctx->session->execute(
MercurySession::RequestType::GET, url, MercurySession::RequestType::GET, url,
[this, timeProvider, callback](MercurySession::Response& res) { [this, timeProvider, callback](MercurySession::Response& res) {
if (res.fail) return; if (res.fail)
return;
char* accessKeyJson = (char*)res.parts[0].data(); char* accessKeyJson = (char*)res.parts[0].data();
auto accessJSON = std::string(accessKeyJson, strrchr(accessKeyJson, '}') - accessKeyJson + 1); auto accessJSON = std::string(
accessKeyJson, strrchr(accessKeyJson, '}') - accessKeyJson + 1);
#ifdef BELL_ONLY_CJSON #ifdef BELL_ONLY_CJSON
cJSON* jsonBody = cJSON_Parse(accessJSON.c_str()); cJSON* jsonBody = cJSON_Parse(accessJSON.c_str());
this->accessKey = cJSON_GetObjectItem(jsonBody, "accessToken")->valuestring; this->accessKey =
cJSON_GetObjectItem(jsonBody, "accessToken")->valuestring;
int expiresIn = cJSON_GetObjectItem(jsonBody, "expiresIn")->valueint; int expiresIn = cJSON_GetObjectItem(jsonBody, "expiresIn")->valueint;
#else #else
auto jsonBody = nlohmann::json::parse(accessJSON); auto jsonBody = nlohmann::json::parse(accessJSON);

View File

@@ -1,5 +1,19 @@
#include "ApResolve.h" #include "ApResolve.h"
#include <initializer_list> // for initializer_list
#include <map> // for operator!=, operator==
#include <memory> // for allocator, unique_ptr
#include <string_view> // for string_view
#include <vector> // for vector
#include "HTTPClient.h" // for HTTPClient, HTTPClient::Response
#ifdef BELL_ONLY_CJSON
#include "cJSON.h"
#else
#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json
#include "nlohmann/json_fwd.hpp" // for json
#endif
using namespace cspot; using namespace cspot;
ApResolve::ApResolve(std::string apOverride) ApResolve::ApResolve(std::string apOverride)
@@ -18,7 +32,7 @@ std::string ApResolve::fetchFirstApAddress()
std::string_view responseStr = request->body(); std::string_view responseStr = request->body();
// parse json with nlohmann // parse json with nlohmann
#if BELL_ONLY_CJSON #ifdef BELL_ONLY_CJSON
cJSON* json = cJSON_Parse(responseStr.data()); cJSON* json = cJSON_Parse(responseStr.data());
auto ap_string = std::string(cJSON_GetArrayItem(cJSON_GetObjectItem(json, "ap_list"), 0)->valuestring); auto ap_string = std::string(cJSON_GetArrayItem(cJSON_GetObjectItem(json, "ap_list"), 0)->valuestring);
cJSON_Delete(json); cJSON_Delete(json);

View File

@@ -1,5 +1,13 @@
#include "AuthChallenges.h" #include "AuthChallenges.h"
#include <algorithm> // for copy
#include <climits> // for CHAR_BIT
#include <random> // for default_random_engine, independent_bits_en...
#include "NanoPBHelper.h" // for pbPutString, pbEncode, pbDecode
#include "pb.h" // for pb_byte_t
#include "pb_decode.h" // for pb_release
using namespace cspot; using namespace cspot;
using random_bytes_engine = using random_bytes_engine =
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>; std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;

View File

@@ -1,5 +1,26 @@
#include "CDNTrackStream.h" #include "CDNTrackStream.h"
#include <string.h> // for memcpy
#include <functional> // for __base
#include <initializer_list> // for initializer_list
#include <map> // for operator!=, operator==
#include <string_view> // for string_view
#include <type_traits> // for remove_extent_t
#include "AccessKeyFetcher.h" // for AccessKeyFetcher
#include "BellLogger.h" // for AbstractLogger
#include "Logger.h" // for CSPOT_LOG
#include "Packet.h" // for cspot
#include "SocketStream.h" // for SocketStream
#include "Utils.h" // for bigNumAdd, bytesToHexString, string...
#include "WrappedSemaphore.h" // for WrappedSemaphore
#ifdef BELL_ONLY_CJSON
#include "cJSON.h"
#else
#include "nlohmann/json.hpp" // for basic_json<>::object_t, basic_json
#include "nlohmann/json_fwd.hpp" // for json
#endif
using namespace cspot; using namespace cspot;
CDNTrackStream::CDNTrackStream( CDNTrackStream::CDNTrackStream(
@@ -10,8 +31,7 @@ CDNTrackStream::CDNTrackStream(
this->crypto = std::make_unique<Crypto>(); this->crypto = std::make_unique<Crypto>();
} }
CDNTrackStream::~CDNTrackStream() { CDNTrackStream::~CDNTrackStream() {}
}
void CDNTrackStream::fail() { void CDNTrackStream::fail() {
this->status = Status::FAILED; this->status = Status::FAILED;
@@ -40,7 +60,9 @@ void CDNTrackStream::fetchFile(const std::vector<uint8_t>& trackId,
#ifdef BELL_ONLY_CJSON #ifdef BELL_ONLY_CJSON
cJSON* jsonResult = cJSON_Parse(result.data()); cJSON* jsonResult = cJSON_Parse(result.data());
std::string cdnUrl = cJSON_GetArrayItem(cJSON_GetObjectItem(jsonResult, "cdnurl"), 0)->valuestring; std::string cdnUrl =
cJSON_GetArrayItem(cJSON_GetObjectItem(jsonResult, "cdnurl"), 0)
->valuestring;
cJSON_Delete(jsonResult); cJSON_Delete(jsonResult);
#else #else
auto jsonResult = nlohmann::json::parse(result); auto jsonResult = nlohmann::json::parse(result);

View File

@@ -1,8 +1,18 @@
#include "LoginBlob.h" #include "LoginBlob.h"
#include "ConstantParameters.h"
#include "Logger.h" #include <stdio.h> // for sprintf
#include <initializer_list> // 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 #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
#endif #endif
using namespace cspot; using namespace cspot;

View File

@@ -1,11 +1,25 @@
#include "MercurySession.h" #include "MercurySession.h"
#include <memory>
#include <mutex> #include <string.h> // for memcpy
#include "BellLogger.h" #include <memory> // for shared_ptr
#include "BellTask.h" #include <mutex> // for scoped_lock
#include "BellUtils.h" #include <stdexcept> // for runtime_error
#include "CSpotContext.h" #include <type_traits> // for remove_extent_t, __underlying_type_impl<>:...
#include "Logger.h" #include <utility> // for pair
#ifndef _WIN32
#include <arpa/inet.h>
#endif
#include "BellLogger.h" // for AbstractLogger
#include "BellTask.h" // for Task
#include "BellUtils.h" // for BELL_SLEEP_MS
#include "Logger.h" // for CSPOT_LOG
#include "NanoPBHelper.h" // for pbPutString, pbDecode, pbEncode
#include "PlainConnection.h" // for PlainConnection
#include "ShannonConnection.h" // for ShannonConnection
#include "TimeProvider.h" // for TimeProvider
#include "Utils.h" // for extract, pack, hton64
using namespace cspot; using namespace cspot;

View File

@@ -1,12 +1,24 @@
#include "PlainConnection.h" #include "PlainConnection.h"
#include <cstring>
#ifndef _WIN32
#include <netdb.h> // for addrinfo, freeaddrinfo, getaddrinfo
#include <netinet/in.h> // for IPPROTO_IP, IPPROTO_TCP
#include <sys/errno.h> // for EAGAIN, EINTR, ETIMEDOUT, errno
#include <sys/socket.h> // for setsockopt, connect, recv, send, shutdown
#include <sys/time.h> // for timeval
#endif
#include <cstring> // for memset
#include <stdexcept> // for runtime_error
#ifdef _WIN32 #ifdef _WIN32
#include <ws2tcpip.h> #include <ws2tcpip.h>
#else #else
#include <netinet/tcp.h> #include <netinet/tcp.h> // for TCP_NODELAY
#include <arpa/inet.h>
#endif #endif
#include <errno.h> #include "BellLogger.h" // for AbstractLogger
#include "Logger.h" #include "Logger.h" // for CSPOT_LOG
#include "Packet.h" // for cspot
#include "Utils.h" // for extract, pack
using namespace cspot; using namespace cspot;

View File

@@ -1,7 +1,20 @@
#include "PlaybackState.h" #include "PlaybackState.h"
#include <memory>
#include "CSpotContext.h" #include <string.h> // for strdup, memcpy, strcpy, strlen
#include "Logger.h" #include <cstdint> // for uint8_t
#include <cstdlib> // for free, NULL, realloc, rand
#include <memory> // for shared_ptr
#include <type_traits> // for remove_extent_t
#include <utility> // for swap
#include "BellLogger.h" // for AbstractLogger
#include "CSpotContext.h" // for Context::ConfigState, Context (ptr o...
#include "ConstantParameters.h" // for protocolVersion, swVersion
#include "Logger.h" // for CSPOT_LOG
#include "NanoPBHelper.h" // for pbEncode, pbPutString
#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
using namespace cspot; using namespace cspot;

View File

@@ -1,6 +1,21 @@
#include "Session.h" #include "Session.h"
#include <memory>
#include "AuthChallenges.h" #include <limits.h> // for CHAR_BIT
#include <cstdint> // for uint8_t
#include <functional> // for __base
#include <memory> // for shared_ptr, unique_ptr, make_unique
#include <random> // for default_random_engine, independent_bi...
#include <type_traits> // for remove_extent_t
#include <utility> // for move
#include "ApResolve.h" // for ApResolve, cspot
#include "AuthChallenges.h" // for AuthChallenges
#include "BellLogger.h" // for AbstractLogger
#include "Logger.h" // for CSPOT_LOG
#include "LoginBlob.h" // for LoginBlob
#include "Packet.h" // for Packet
#include "PlainConnection.h" // for PlainConnection, timeoutCallback
#include "ShannonConnection.h" // for ShannonConnection
using random_bytes_engine = using random_bytes_engine =
std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>; std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t>;

View File

@@ -1,9 +1,7 @@
#include "Shannon.h" #include "Shannon.h"
// #include <bit>
#include <stdint.h> // for uint32_t
#include <limits.h> // for CHAR_BIT #include <limits.h> // for CHAR_BIT
// #define NDEBUG #include <stddef.h> // for size_t
#include <assert.h>
using std::size_t; using std::size_t;

View File

@@ -1,5 +1,17 @@
#include "ShannonConnection.h" #include "ShannonConnection.h"
#include "Packet.h"
#include <type_traits> // for remove_extent_t
#ifndef _WIN32
#include <arpa/inet.h>
#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
using namespace cspot; using namespace cspot;

View File

@@ -1,14 +1,22 @@
#include "SpircHandler.h" #include "SpircHandler.h"
#include <memory>
#include "AccessKeyFetcher.h" #include <cstdint> // for uint8_t
#include "BellUtils.h" #include <memory> // for shared_ptr, make_unique, unique_ptr
#include "CSpotContext.h" #include <type_traits> // for remove_extent_t
#include "Logger.h" #include <utility> // for move
#include "MercurySession.h"
#include "PlaybackState.h" #include "BellLogger.h" // for AbstractLogger
#include "TrackPlayer.h" #include "CSpotContext.h" // for Context::ConfigState, Context (ptr only)
#include "TrackReference.h" #include "Logger.h" // for CSPOT_LOG
#include "protobuf/spirc.pb.h" #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 "TrackReference.h" // for TrackReference
#include "Utils.h" // for stringHexToBytes
#include "pb_decode.h" // for pb_release
#include "protobuf/spirc.pb.h" // for Frame, State, Frame_fields, MessageTy...
using namespace cspot; using namespace cspot;
@@ -155,9 +163,9 @@ void SpircHandler::handleFrame(std::vector<uint8_t>& data) {
* when last track has been reached, we has to restart as we can't tell the difference */ * when last track has been reached, we has to restart as we can't tell the difference */
if ((!isNextTrackPreloaded && this->playbackState.getNextTrackRef()) || isRequestedFromLoad) { if ((!isNextTrackPreloaded && this->playbackState.getNextTrackRef()) || isRequestedFromLoad) {
CSPOT_LOG(debug, "Seek command while streaming current"); CSPOT_LOG(debug, "Seek command while streaming current");
sendEvent(EventType::SEEK, (int)playbackState.remoteFrame.position);
playbackState.updatePositionMs(playbackState.remoteFrame.position); playbackState.updatePositionMs(playbackState.remoteFrame.position);
trackPlayer->seekMs(playbackState.remoteFrame.position); trackPlayer->seekMs(playbackState.remoteFrame.position);
sendEvent(EventType::SEEK, (int)playbackState.remoteFrame.position);
} else { } else {
CSPOT_LOG(debug, "Seek command while streaming next or before started"); CSPOT_LOG(debug, "Seek command while streaming next or before started");
isRequestedFromLoad = true; isRequestedFromLoad = true;

View File

@@ -1,5 +1,12 @@
#include "TimeProvider.h" #include "TimeProvider.h"
#include "Logger.h"
#ifndef _WIN32
#include <arpa/inet.h>
#endif
#include "BellLogger.h" // for AbstractLogger
#include "Logger.h" // for CSPOT_LOG
#include "Utils.h" // for extract, getCurrentTimestamp
using namespace cspot; using namespace cspot;

View File

@@ -1,12 +1,22 @@
#include "TrackPlayer.h" #include "TrackPlayer.h"
#include <cstddef>
#include <fstream> #include <mutex> // for mutex, scoped_lock
#include <memory> #include <string> // for string
#include <mutex> #include <type_traits> // for remove_extent_t
#include <vector> #include <vector> // for vector, vector<>::value_type
#include "CDNTrackStream.h"
#include "Logger.h" #include "BellLogger.h" // for AbstractLogger
#include "TrackReference.h" #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 "WrappedSemaphore.h" // for WrappedSemaphore
namespace cspot {
struct Context;
struct TrackReference;
} // namespace cspot
using namespace cspot; using namespace cspot;

View File

@@ -1,12 +1,26 @@
#include "TrackProvider.h" #include "TrackProvider.h"
#include <memory>
#include "AccessKeyFetcher.h" #include <assert.h> // for assert
#include "CDNTrackStream.h" #include <string.h> // for strlen
#include "Logger.h" #include <cstdint> // for uint8_t
#include "MercurySession.h" #include <functional> // for __base
#include "TrackReference.h" #include <memory> // for shared_ptr, weak_ptr, make_shared
#include "Utils.h" #include <string> // for string, operator+
#include "protobuf/metadata.pb.h" #include <type_traits> // for remove_extent_t
#include "AccessKeyFetcher.h" // for AccessKeyFetcher
#include "BellLogger.h" // for AbstractLogger
#include "CDNTrackStream.h" // for CDNTrackStream, CDNTrackStream::Tr...
#include "CSpotContext.h" // for Context::ConfigState, Context (ptr...
#include "Logger.h" // for CSPOT_LOG
#include "MercurySession.h" // for MercurySession, MercurySession::Da...
#include "NanoPBHelper.h" // for pbArrayToVector, pbDecode
#include "Packet.h" // for cspot
#include "TrackReference.h" // for TrackReference, TrackReference::Type
#include "Utils.h" // for bytesToHexString, string_format
#include "WrappedSemaphore.h" // for WrappedSemaphore
#include "pb_decode.h" // for pb_release
#include "protobuf/metadata.pb.h" // for Track, _Track, AudioFile, Episode
using namespace cspot; using namespace cspot;
@@ -21,9 +35,11 @@ TrackProvider::TrackProvider(std::shared_ptr<cspot::Context> ctx) {
TrackProvider::~TrackProvider() { TrackProvider::~TrackProvider() {
pb_release(Track_fields, &trackInfo); pb_release(Track_fields, &trackInfo);
pb_release(Episode_fields, &trackInfo);
} }
std::shared_ptr<cspot::CDNTrackStream> TrackProvider::loadFromTrackRef(TrackReference& trackRef) { std::shared_ptr<cspot::CDNTrackStream> TrackProvider::loadFromTrackRef(
TrackReference& trackRef) {
auto track = std::make_shared<cspot::CDNTrackStream>(this->accessKeyFetcher); auto track = std::make_shared<cspot::CDNTrackStream>(this->accessKeyFetcher);
this->currentTrackReference = track; this->currentTrackReference = track;
this->trackIdInfo = trackRef; this->trackIdInfo = trackRef;
@@ -34,7 +50,8 @@ std::shared_ptr<cspot::CDNTrackStream> TrackProvider::loadFromTrackRef(TrackRefe
void TrackProvider::queryMetadata() { void TrackProvider::queryMetadata() {
std::string requestUrl = string_format( std::string requestUrl = string_format(
"hm://metadata/3/%s/%s", trackIdInfo.type == TrackReference::Type::TRACK ? "track" : "episode", "hm://metadata/3/%s/%s",
trackIdInfo.type == TrackReference::Type::TRACK ? "track" : "episode",
bytesToHexString(trackIdInfo.gid).c_str()); bytesToHexString(trackIdInfo.gid).c_str());
CSPOT_LOG(debug, "Requesting track metadata from %s", requestUrl.c_str()); CSPOT_LOG(debug, "Requesting track metadata from %s", requestUrl.c_str());
@@ -50,54 +67,40 @@ void TrackProvider::queryMetadata() {
void TrackProvider::onMetadataResponse(MercurySession::Response& res) { void TrackProvider::onMetadataResponse(MercurySession::Response& res) {
CSPOT_LOG(debug, "Got track metadata response"); CSPOT_LOG(debug, "Got track metadata response");
pb_release(Track_fields, &trackInfo); int alternativeCount, filesCount = 0;
pbDecode(trackInfo, Track_fields, res.parts[0]); bool canPlay = false;
AudioFile* selectedFiles;
std::vector<uint8_t> trackId, fileId;
if (trackIdInfo.type == TrackReference::Type::TRACK) {
pb_release(Track_fields, &trackInfo);
assert(res.parts.size() > 0);
pbDecode(trackInfo, Track_fields, res.parts[0]);
CSPOT_LOG(info, "Track name: %s", trackInfo.name); CSPOT_LOG(info, "Track name: %s", trackInfo.name);
CSPOT_LOG(info, "Track duration: %d", trackInfo.duration); CSPOT_LOG(info, "Track duration: %d", trackInfo.duration);
CSPOT_LOG(debug, "trackInfo.restriction.size() = %d", CSPOT_LOG(debug, "trackInfo.restriction.size() = %d",
trackInfo.restriction_count); trackInfo.restriction_count);
int altIndex = -1; if (doRestrictionsApply(trackInfo.restriction,
while (!canPlayTrack(altIndex)) { trackInfo.restriction_count)) {
altIndex++; // Go through alternatives
CSPOT_LOG(info, "Trying alternative %d", altIndex); for (int x = 0; x < trackInfo.alternative_count; x++) {
if (!doRestrictionsApply(trackInfo.alternative[x].restriction,
if (altIndex >= trackInfo.alternative_count) { trackInfo.alternative[x].restriction_count)) {
// no alternatives for song selectedFiles = trackInfo.alternative[x].file;
if (!this->currentTrackReference.expired()) { filesCount = trackInfo.alternative[x].file_count;
auto trackRef = this->currentTrackReference.lock(); trackId = pbArrayToVector(trackInfo.alternative[x].gid);
trackRef->status = CDNTrackStream::Status::FAILED; break;
trackRef->trackReady->give();
}
return;
}
}
std::vector<uint8_t> trackId;
std::vector<uint8_t> fileId;
if (altIndex < 0) {
trackId = pbArrayToVector(trackInfo.gid);
for (int x = 0; x < trackInfo.file_count; x++) {
if (trackInfo.file[x].format == ctx->config.audioFormat) {
fileId = pbArrayToVector(trackInfo.file[x].file_id);
break; // If file found stop searching
} }
} }
} else { } else {
trackId = pbArrayToVector(trackInfo.alternative[altIndex].gid); selectedFiles = trackInfo.file;
for (int x = 0; x < trackInfo.alternative[altIndex].file_count; x++) { filesCount = trackInfo.file_count;
if (trackInfo.alternative[altIndex].file[x].format == ctx->config.audioFormat) { trackId = pbArrayToVector(trackInfo.gid);
fileId =
pbArrayToVector(trackInfo.alternative[altIndex].file[x].file_id);
break; // If file found stop searching
}
}
} }
if (!this->currentTrackReference.expired()) { // Set track's metadata
auto trackRef = this->currentTrackReference.lock(); auto trackRef = this->currentTrackReference.lock();
auto imageId = auto imageId =
@@ -110,6 +113,60 @@ void TrackProvider::onMetadataResponse(MercurySession::Response& res) {
trackRef->trackInfo.imageUrl = trackRef->trackInfo.imageUrl =
"https://i.scdn.co/image/" + bytesToHexString(imageId); "https://i.scdn.co/image/" + bytesToHexString(imageId);
trackRef->trackInfo.duration = trackInfo.duration; trackRef->trackInfo.duration = trackInfo.duration;
} else {
pb_release(Episode_fields, &episodeInfo);
assert(res.parts.size() > 0);
pbDecode(episodeInfo, Episode_fields, res.parts[0]);
CSPOT_LOG(info, "Episode name: %s", episodeInfo.name);
CSPOT_LOG(info, "Episode duration: %d", episodeInfo.duration);
CSPOT_LOG(debug, "episodeInfo.restriction.size() = %d",
episodeInfo.restriction_count);
if (!doRestrictionsApply(episodeInfo.restriction,
episodeInfo.restriction_count)) {
selectedFiles = episodeInfo.file;
filesCount = episodeInfo.file_count;
trackId = pbArrayToVector(episodeInfo.gid);
}
auto trackRef = this->currentTrackReference.lock();
auto imageId = pbArrayToVector(episodeInfo.covers->image[0].file_id);
trackRef->trackInfo.trackId = bytesToHexString(trackIdInfo.gid);
trackRef->trackInfo.name = std::string(episodeInfo.name);
trackRef->trackInfo.album = "";
trackRef->trackInfo.artist = "",
trackRef->trackInfo.imageUrl =
"https://i.scdn.co/image/" + bytesToHexString(imageId);
trackRef->trackInfo.duration = episodeInfo.duration;
}
for (int x = 0; x < filesCount; x++) {
CSPOT_LOG(debug, "File format: %d", selectedFiles[x].format);
if (selectedFiles[x].format == ctx->config.audioFormat) {
fileId = pbArrayToVector(selectedFiles[x].file_id);
break; // If file found stop searching
}
// Fallback to OGG Vorbis 96kbps
if (fileId.size() == 0 &&
selectedFiles[x].format == AudioFormat_OGG_VORBIS_96) {
fileId = pbArrayToVector(selectedFiles[x].file_id);
}
}
// No viable files found for playback
if (fileId.size() == 0) {
CSPOT_LOG(info, "File not available for playback");
// no alternatives for song
if (!this->currentTrackReference.expired()) {
auto trackRef = this->currentTrackReference.lock();
trackRef->status = CDNTrackStream::Status::FAILED;
trackRef->trackReady->give();
}
return;
} }
this->fetchFile(fileId, trackId); this->fetchFile(fileId, trackId);
@@ -147,20 +204,25 @@ bool countryListContains(char* countryList, char* country) {
return false; return false;
} }
bool TrackProvider::canPlayTrack(int altIndex) { bool TrackProvider::doRestrictionsApply(Restriction* restrictions, int count) {
if (altIndex < 0) { for (int x = 0; x < count; x++) {
for (int x = 0; x < trackInfo.restriction_count; x++) { if (restrictions[x].countries_allowed != nullptr) {
if (trackInfo.restriction[x].countries_allowed != nullptr) { return !countryListContains(restrictions[x].countries_allowed,
return countryListContains(trackInfo.restriction[x].countries_allowed,
(char*)ctx->config.countryCode.c_str()); (char*)ctx->config.countryCode.c_str());
} }
if (trackInfo.restriction[x].countries_forbidden != nullptr) { if (restrictions[x].countries_forbidden != nullptr) {
return !countryListContains( return countryListContains(restrictions[x].countries_forbidden,
trackInfo.restriction[x].countries_forbidden,
(char*)ctx->config.countryCode.c_str()); (char*)ctx->config.countryCode.c_str());
} }
} }
return false;
}
bool TrackProvider::canPlayTrack(int altIndex) {
if (altIndex < 0) {
} else { } else {
for (int x = 0; x < trackInfo.alternative[altIndex].restriction_count; for (int x = 0; x < trackInfo.alternative[altIndex].restriction_count;
x++) { x++) {

View File

@@ -1,15 +1,20 @@
#include "Utils.h" #include "Utils.h"
#include <cstring>
#include <memory>
#include <chrono>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
unsigned long long getCurrentTimestamp() #include <stdlib.h> // for strtol
{ #include <iomanip> // for operator<<, setfill, setw
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); #include <iostream> // for basic_ostream, hex
#include <sstream> // for stringstream
#include <string> // for string
#include <type_traits> // for enable_if<>::type
#include <chrono>
#ifndef _WIN32
#include <arpa/inet.h>
#endif
unsigned long long getCurrentTimestamp() {
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
} }
uint64_t hton64(uint64_t value) { uint64_t hton64(uint64_t value) {
@@ -48,26 +53,20 @@ std::string bytesToHexString(const std::vector<uint8_t>& v) {
return ss.str(); return ss.str();
} }
std::vector<uint8_t> bigNumAdd(std::vector<uint8_t> num, int n) std::vector<uint8_t> bigNumAdd(std::vector<uint8_t> num, int n) {
{
auto carry = n; auto carry = n;
for (int x = num.size() - 1; x >= 0; x--) for (int x = num.size() - 1; x >= 0; x--) {
{
int res = num[x] + carry; int res = num[x] + carry;
if (res < 256) if (res < 256) {
{
carry = 0; carry = 0;
num[x] = res; num[x] = res;
} } else {
else
{
// Carry the rest of the division // Carry the rest of the division
carry = res / 256; carry = res / 256;
num[x] = res % 256; num[x] = res % 256;
// extend the vector at the last index // extend the vector at the last index
if (x == 0) if (x == 0) {
{
num.insert(num.begin(), carry); num.insert(num.begin(), carry);
return num; return num;
} }
@@ -77,19 +76,14 @@ std::vector<uint8_t> bigNumAdd(std::vector<uint8_t> num, int n)
return num; return num;
} }
std::vector<uint8_t> bigNumDivide(std::vector<uint8_t> num, int n) std::vector<uint8_t> bigNumDivide(std::vector<uint8_t> num, int n) {
{
auto carry = 0; auto carry = 0;
for (int x = 0; x < num.size(); x++) for (int x = 0; x < num.size(); x++) {
{
int res = num[x] + carry * 256; int res = num[x] + carry * 256;
if (res < n) if (res < n) {
{
carry = res; carry = res;
num[x] = 0; num[x] = 0;
} } else {
else
{
// Carry the rest of the division // Carry the rest of the division
carry = res % n; carry = res % n;
num[x] = res / n; num[x] = res / n;
@@ -99,26 +93,20 @@ std::vector<uint8_t> bigNumDivide(std::vector<uint8_t> num, int n)
return num; return num;
} }
std::vector<uint8_t> bigNumMultiply(std::vector<uint8_t> num, int n) std::vector<uint8_t> bigNumMultiply(std::vector<uint8_t> num, int n) {
{
auto carry = 0; auto carry = 0;
for (int x = num.size() - 1; x >= 0; x--) for (int x = num.size() - 1; x >= 0; x--) {
{
int res = num[x] * n + carry; int res = num[x] * n + carry;
if (res < 256) if (res < 256) {
{
carry = 0; carry = 0;
num[x] = res; num[x] = res;
} } else {
else
{
// Carry the rest of the division // Carry the rest of the division
carry = res / 256; carry = res / 256;
num[x] = res % 256; num[x] = res % 256;
// extend the vector at the last index // extend the vector at the last index
if (x == 0) if (x == 0) {
{
num.insert(num.begin(), carry); num.insert(num.begin(), carry);
return num; return num;
} }
@@ -127,8 +115,7 @@ std::vector<uint8_t> bigNumMultiply(std::vector<uint8_t> num, int n)
return num; return num;
} }
unsigned char h2int(char c) unsigned char h2int(char c) {
{
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
return ((unsigned char)c - '0'); return ((unsigned char)c - '0');
} }
@@ -141,8 +128,7 @@ unsigned char h2int(char c)
return (0); return (0);
} }
std::string urlDecode(std::string str) std::string urlDecode(std::string str) {
{
std::string encodedString = ""; std::string encodedString = "";
char c; char c;
char code0; char code0;

View File

@@ -54,7 +54,6 @@ struct opus {
size_t overframes; size_t overframes;
u8_t *overbuf; u8_t *overbuf;
int channels; int channels;
bool eos;
}; };
#if !LINKALL #if !LINKALL
@@ -133,7 +132,7 @@ static opus_uint32 parse_uint32(const unsigned char* _data) {
} }
static int get_opus_packet(void) { static int get_opus_packet(void) {
int status = 0; int status, packet = -1;
LOCK_S; LOCK_S;
size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
@@ -153,8 +152,12 @@ static int get_opus_packet(void) {
if (status) OG(&go, stream_pagein, &u->state, &u->page); if (status) OG(&go, stream_pagein, &u->state, &u->page);
} }
// only return a negative value when end of streaming is reached
if (status > 0) packet = status;
else if (stream.state > DISCONNECT) packet = 0;
UNLOCK_S; UNLOCK_S;
return status; return packet;
} }
static int read_opus_header(void) { static int read_opus_header(void) {
@@ -219,7 +222,6 @@ static int read_opus_header(void) {
static decode_state opus_decompress(void) { static decode_state opus_decompress(void) {
frames_t frames; frames_t frames;
int n;
u8_t *write_buf; u8_t *write_buf;
if (decode.new_stream) { if (decode.new_stream) {
@@ -258,6 +260,8 @@ static decode_state opus_decompress(void) {
write_buf = process.inbuf; write_buf = process.inbuf;
); );
int packet, n = 0;
// get some packets and decode them, or use the leftover from previous pass // get some packets and decode them, or use the leftover from previous pass
if (u->overframes) { if (u->overframes) {
/* use potential leftover from previous encoding. We know that it will fit this time /* use potential leftover from previous encoding. We know that it will fit this time
@@ -265,7 +269,7 @@ static decode_state opus_decompress(void) {
memcpy(write_buf, u->overbuf, u->overframes * BYTES_PER_FRAME); memcpy(write_buf, u->overbuf, u->overframes * BYTES_PER_FRAME);
n = u->overframes; n = u->overframes;
u->overframes = 0; u->overframes = 0;
} else if (get_opus_packet() > 0) { } else if ((packet = get_opus_packet()) > 0) {
if (frames < MAX_OPUS_FRAMES) { if (frames < MAX_OPUS_FRAMES) {
// don't have enough contiguous space, use the overflow buffer // don't have enough contiguous space, use the overflow buffer
n = OP(&gu, decode, u->decoder, u->packet.packet, u->packet.bytes, (opus_int16*) u->overbuf, MAX_OPUS_FRAMES, 0); n = OP(&gu, decode, u->decoder, u->packet.packet, u->packet.bytes, (opus_int16*) u->overbuf, MAX_OPUS_FRAMES, 0);
@@ -280,10 +284,10 @@ static decode_state opus_decompress(void) {
* outputbuf and streambuf for maybe a long time while we process it all, so don't do that */ * outputbuf and streambuf for maybe a long time while we process it all, so don't do that */
n = OP(&gu, decode, u->decoder, u->packet.packet, u->packet.bytes, (opus_int16*) write_buf, frames, 0); n = OP(&gu, decode, u->decoder, u->packet.packet, u->packet.bytes, (opus_int16*) write_buf, frames, 0);
} }
} else if (!OG(&go, page_eos, &u->page)) { } else if (!packet && !OG(&go, page_eos, &u->page)) {
UNLOCK_O_direct; UNLOCK_O_direct;
return DECODE_RUNNING; return DECODE_RUNNING;
} else u->eos = true; }
if (n > 0) { if (n > 0) {
frames_t count; frames_t count;
@@ -326,7 +330,7 @@ static decode_state opus_decompress(void) {
} else if (n == 0) { } else if (n == 0) {
if (stream.state <= DISCONNECT && u->eos) { if (packet < 0) {
LOG_INFO("end of decode"); LOG_INFO("end of decode");
UNLOCK_O_direct; UNLOCK_O_direct;
return DECODE_COMPLETE; return DECODE_COMPLETE;
@@ -351,7 +355,6 @@ static void opus_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
if (!u->overbuf) u->overbuf = malloc(MAX_OPUS_FRAMES * BYTES_PER_FRAME); if (!u->overbuf) u->overbuf = malloc(MAX_OPUS_FRAMES * BYTES_PER_FRAME);
u->eos = false;
u->status = OGG_SYNC; u->status = OGG_SYNC;
u->overframes = 0; u->overframes = 0;

View File

@@ -65,7 +65,6 @@ struct vorbis {
}; };
int rate, channels; int rate, channels;
uint32_t overflow; uint32_t overflow;
bool eos;
}; };
#if !LINKALL #if !LINKALL
@@ -133,7 +132,7 @@ extern struct processstate process;
#endif #endif
static int get_ogg_packet(void) { static int get_ogg_packet(void) {
int status = 0; int status, packet = -1;
LOCK_S; LOCK_S;
size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf));
@@ -153,8 +152,12 @@ static int get_ogg_packet(void) {
if (status) OG(&go, stream_pagein, &v->state, &v->page); if (status) OG(&go, stream_pagein, &v->state, &v->page);
} }
// only return a negative value when end of streaming is reached
if (status > 0) packet = status;
else if (stream.state > DISCONNECT) packet = 0;
UNLOCK_S; UNLOCK_S;
return status; return packet;
} }
static int read_vorbis_header(void) { static int read_vorbis_header(void) {
@@ -261,9 +264,7 @@ inline int pcm_out(vorbis_dsp_state* decoder, void*** pcm) {
static decode_state vorbis_decode(void) { static decode_state vorbis_decode(void) {
frames_t frames; frames_t frames;
int n = 0;
u8_t *write_buf; u8_t *write_buf;
void** pcm = NULL;
if (decode.new_stream) { if (decode.new_stream) {
int status = read_vorbis_header(); int status = read_vorbis_header();
@@ -301,18 +302,21 @@ static decode_state vorbis_decode(void) {
write_buf = process.inbuf; write_buf = process.inbuf;
); );
void** pcm = NULL;
int packet, n = 0;
if (v->overflow) { if (v->overflow) {
n = pcm_out(&v->decoder, &pcm); n = pcm_out(&v->decoder, &pcm);
v->overflow = n - min(n, frames); v->overflow = n - min(n, frames);
} else if (get_ogg_packet() > 0) { } else if ((packet = get_ogg_packet()) > 0) {
n = OV(&gv, synthesis, &v->block, &v->packet); n = OV(&gv, synthesis, &v->block, &v->packet);
if (n == 0) n = OV(&gv, synthesis_blockin, &v->decoder, &v->block); if (n == 0) n = OV(&gv, synthesis_blockin, &v->decoder, &v->block);
if (n == 0) n = pcm_out(&v->decoder, &pcm); if (n == 0) n = pcm_out(&v->decoder, &pcm);
v->overflow = n - min(n, frames); v->overflow = n - min(n, frames);
} else if (!OG(&go, page_eos, &v->page)) { } else if (!packet && !OG(&go, page_eos, &v->page)) {
UNLOCK_O_direct; UNLOCK_O_direct;
return DECODE_RUNNING; return DECODE_RUNNING;
} else v->eos = true; }
if (n > 0) { if (n > 0) {
ISAMPLE_T *optr = (ISAMPLE_T*) write_buf; ISAMPLE_T *optr = (ISAMPLE_T*) write_buf;
@@ -370,7 +374,7 @@ static decode_state vorbis_decode(void) {
} else if (n == 0) { } else if (n == 0) {
if (stream.state <= DISCONNECT && v->eos) { if (packet < 0) {
LOG_INFO("end of decode"); LOG_INFO("end of decode");
UNLOCK_O_direct; UNLOCK_O_direct;
return DECODE_COMPLETE; return DECODE_COMPLETE;
@@ -397,7 +401,6 @@ static void vorbis_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
OV(&go, dsp_clear, &v->decoder); OV(&go, dsp_clear, &v->decoder);
} }
v->eos = false;
v->opened = false; v->opened = false;
v->status = OGG_SYNC; v->status = OGG_SYNC;
v->overflow = 0; v->overflow = 0;

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -43,6 +43,9 @@ declare function getStatus(): {};
declare function getStatus(): {}; declare function getStatus(): {};
declare function getStatus(): {}; declare function getStatus(): {};
declare function getStatus(): {}; declare function getStatus(): {};
declare function getStatus(): {};
declare function getStatus(): {};
declare function getStatus(): {};
declare function getRadioButton(entry: any): string; declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string; declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string; declare function getRadioButton(entry: any): string;
@@ -88,6 +91,12 @@ declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string; declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string; declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string; declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function getRadioButton(entry: any): string;
declare function pushStatus(): void;
declare function pushStatus(): void;
declare function pushStatus(): void;
declare function pushStatus(): void; declare function pushStatus(): void;
declare function pushStatus(): void; declare function pushStatus(): void;
declare function pushStatus(): void; declare function pushStatus(): void;

View File

@@ -1,5 +1,5 @@
target_add_binary_data( __idf_wifi-manager webapp/dist/css/index.cd56ff129e3113d8cd3a.css.gz BINARY) target_add_binary_data( __idf_wifi-manager webapp/dist/css/index.cd56ff129e3113d8cd3a.css.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/favicon-32x32.png BINARY) target_add_binary_data( __idf_wifi-manager webapp/dist/favicon-32x32.png BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/index.html.gz BINARY) target_add_binary_data( __idf_wifi-manager webapp/dist/index.html.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/js/index.b79c88.bundle.js.gz BINARY) target_add_binary_data( __idf_wifi-manager webapp/dist/js/index.997af2.bundle.js.gz BINARY)
target_add_binary_data( __idf_wifi-manager webapp/dist/js/node_vendors.b79c88.bundle.js.gz BINARY) target_add_binary_data( __idf_wifi-manager webapp/dist/js/node_vendors.997af2.bundle.js.gz BINARY)

View File

@@ -6,29 +6,29 @@ extern const uint8_t _favicon_32x32_png_start[] asm("_binary_favicon_32x32_png_s
extern const uint8_t _favicon_32x32_png_end[] asm("_binary_favicon_32x32_png_end"); extern const uint8_t _favicon_32x32_png_end[] asm("_binary_favicon_32x32_png_end");
extern const uint8_t _index_html_gz_start[] asm("_binary_index_html_gz_start"); extern const uint8_t _index_html_gz_start[] asm("_binary_index_html_gz_start");
extern const uint8_t _index_html_gz_end[] asm("_binary_index_html_gz_end"); extern const uint8_t _index_html_gz_end[] asm("_binary_index_html_gz_end");
extern const uint8_t _index_b79c88_bundle_js_gz_start[] asm("_binary_index_b79c88_bundle_js_gz_start"); extern const uint8_t _index_997af2_bundle_js_gz_start[] asm("_binary_index_997af2_bundle_js_gz_start");
extern const uint8_t _index_b79c88_bundle_js_gz_end[] asm("_binary_index_b79c88_bundle_js_gz_end"); extern const uint8_t _index_997af2_bundle_js_gz_end[] asm("_binary_index_997af2_bundle_js_gz_end");
extern const uint8_t _node_vendors_b79c88_bundle_js_gz_start[] asm("_binary_node_vendors_b79c88_bundle_js_gz_start"); extern const uint8_t _node_vendors_997af2_bundle_js_gz_start[] asm("_binary_node_vendors_997af2_bundle_js_gz_start");
extern const uint8_t _node_vendors_b79c88_bundle_js_gz_end[] asm("_binary_node_vendors_b79c88_bundle_js_gz_end"); extern const uint8_t _node_vendors_997af2_bundle_js_gz_end[] asm("_binary_node_vendors_997af2_bundle_js_gz_end");
const char * resource_lookups[] = { const char * resource_lookups[] = {
"/css/index.cd56ff129e3113d8cd3a.css.gz", "/css/index.cd56ff129e3113d8cd3a.css.gz",
"/favicon-32x32.png", "/favicon-32x32.png",
"/index.html.gz", "/index.html.gz",
"/js/index.b79c88.bundle.js.gz", "/js/index.997af2.bundle.js.gz",
"/js/node_vendors.b79c88.bundle.js.gz", "/js/node_vendors.997af2.bundle.js.gz",
"" ""
}; };
const uint8_t * resource_map_start[] = { const uint8_t * resource_map_start[] = {
_index_cd56ff129e3113d8cd3a_css_gz_start, _index_cd56ff129e3113d8cd3a_css_gz_start,
_favicon_32x32_png_start, _favicon_32x32_png_start,
_index_html_gz_start, _index_html_gz_start,
_index_b79c88_bundle_js_gz_start, _index_997af2_bundle_js_gz_start,
_node_vendors_b79c88_bundle_js_gz_start _node_vendors_997af2_bundle_js_gz_start
}; };
const uint8_t * resource_map_end[] = { const uint8_t * resource_map_end[] = {
_index_cd56ff129e3113d8cd3a_css_gz_end, _index_cd56ff129e3113d8cd3a_css_gz_end,
_favicon_32x32_png_end, _favicon_32x32_png_end,
_index_html_gz_end, _index_html_gz_end,
_index_b79c88_bundle_js_gz_end, _index_997af2_bundle_js_gz_end,
_node_vendors_b79c88_bundle_js_gz_end _node_vendors_997af2_bundle_js_gz_end
}; };

View File

@@ -1,6 +1,6 @@
/*********************************** /***********************************
webpack_headers webpack_headers
dist/css/index.cd56ff129e3113d8cd3a.css.gz,dist/favicon-32x32.png,dist/index.html.gz,dist/js/index.b79c88.bundle.js.gz,dist/js/node_vendors.b79c88.bundle.js.gz dist/css/index.cd56ff129e3113d8cd3a.css.gz,dist/favicon-32x32.png,dist/index.html.gz,dist/js/index.997af2.bundle.js.gz,dist/js/node_vendors.997af2.bundle.js.gz
***********************************/ ***********************************/
#pragma once #pragma once
#include <inttypes.h> #include <inttypes.h>

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
server_certs/r2m01.cer.5 Normal file

Binary file not shown.

BIN
server_certs/r2m01.cer.6 Normal file

Binary file not shown.

BIN
server_certs/r2m01.cer.7 Normal file

Binary file not shown.