mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-07 20:17:04 +03:00
Merge remote-tracking branch 'origin/master-v4.3' into master-v4.3
This commit is contained in:
@@ -119,8 +119,8 @@ static void cspotTask(void *pvParameters) {
|
||||
switch (event.eventType) {
|
||||
case CSpotEventType::TRACK_INFO: {
|
||||
TrackInfo track = std::get<TrackInfo>(event.data);
|
||||
// duration is in chunks of 0.5 ms
|
||||
cspot.cHandler(CSPOT_TRACK, 44100, track.duration / 2, track.artist.c_str(), track.album.c_str(), track.name.c_str());
|
||||
cspot.cHandler(CSPOT_TRACK, 44100, track.duration, track.artist.c_str(),
|
||||
track.album.c_str(), track.name.c_str(), track.imageUrl.c_str());
|
||||
break;
|
||||
}
|
||||
case CSpotEventType::PLAY_PAUSE: {
|
||||
@@ -192,7 +192,7 @@ struct cspot_s* cspot_create(const char *name, cspot_cmd_cb_t cmd_cb, cspot_data
|
||||
cspot.cHandler = cmd_cb;
|
||||
cspot.dHandler = data_cb;
|
||||
strncpy(cspot.name, name, sizeof(cspot.name) - 1);
|
||||
cspot.TaskHandle = xTaskCreateStatic(&cspotTask, "cspot", CSPOT_STACK_SIZE, NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT, xStack, &xTaskBuffer);
|
||||
cspot.TaskHandle = xTaskCreateStatic(&cspotTask, "cspot", CSPOT_STACK_SIZE, NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT - 2, xStack, &xTaskBuffer);
|
||||
|
||||
return &cspot;
|
||||
}
|
||||
|
||||
@@ -45,5 +45,6 @@ endif()
|
||||
add_library(cspot STATIC ${SOURCES} ${PROTO_SRCS})
|
||||
# PUBLIC to propagate includes from bell to cspot dependents
|
||||
target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC)
|
||||
target_compile_definitions(bell PUBLIC PB_FIELD_32BIT)
|
||||
target_link_libraries(cspot PUBLIC ${EXTRA_LIBS})
|
||||
target_include_directories(cspot PUBLIC "include" ${GENERATED_INCLUDES} ${NANOPB_INCLUDE_DIRS})
|
||||
|
||||
@@ -7,8 +7,6 @@ option(BELL_DISABLE_CODECS "Disable libhelix AAC and MP3 codecs" OFF)
|
||||
#set(BELL_EXTERNAL_CJSON "" CACHE STRING "External cJSON library target name, optional")
|
||||
#set(BELL_EXTERNAL_TREMOR "" CACHE STRING "External tremor library target name, optional")
|
||||
|
||||
add_definitions(-DPB_ENABLE_MALLOC)
|
||||
|
||||
# Include nanoPB library
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/nanopb/extra)
|
||||
find_package(Nanopb REQUIRED)
|
||||
@@ -98,3 +96,4 @@ message(${NANOPB_INCLUDE_DIRS})
|
||||
# PUBLIC to propagate esp-idf includes to bell dependents
|
||||
target_link_libraries(bell PUBLIC ${EXTRA_LIBS})
|
||||
target_include_directories(bell PUBLIC "include" ${EXTRA_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC)
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
std::vector<uint8_t> sha1HMAC(const std::vector<uint8_t>& inputKey, const std::vector<uint8_t>& message);
|
||||
|
||||
// AES CTR
|
||||
void aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, std::vector<uint8_t>& data);
|
||||
void aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, uint8_t* data, size_t nbytes);
|
||||
|
||||
// AES ECB
|
||||
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
std::vector<uint8_t> sha1HMAC(const std::vector<uint8_t>& inputKey, const std::vector<uint8_t>& message);
|
||||
|
||||
// AES CTR
|
||||
void aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, std::vector<uint8_t>& data);
|
||||
void aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, uint8_t* buffer, size_t nbytes);
|
||||
|
||||
// AES ECB
|
||||
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
|
||||
|
||||
@@ -42,6 +42,10 @@ void pbDecode(T &result, const pb_msgdesc_t *fields, std::vector<uint8_t> &data)
|
||||
}
|
||||
}
|
||||
|
||||
void pbPutString(const std::string &stringToPack, char* dst);
|
||||
void pbPutCharArray(const char * stringToPack, char* dst);
|
||||
void pbPutBytes(const std::vector<uint8_t> &data, pb_bytes_array_t &dst);
|
||||
|
||||
const char* pb_encode_to_string(const pb_msgdesc_t *fields, const void *data);
|
||||
pb_istream_t pb_istream_from_http(bell::HTTPClient::HTTPResponse *response, size_t length = 0);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace bell
|
||||
#ifdef ESP_PLATFORM
|
||||
this->xStack = NULL;
|
||||
this->priority = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + priority;
|
||||
if (this->priority < 0) this->priority = ESP_TASK_PRIO_MIN;
|
||||
if (this->priority <= ESP_TASK_PRIO_MIN) this->priority = ESP_TASK_PRIO_MIN + 1;
|
||||
if (runOnPSRAM) {
|
||||
this->xStack = (StackType_t*) heap_caps_malloc(this->stackSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ std::vector<uint8_t> CryptoMbedTLS::sha1HMAC(const std::vector<uint8_t> &inputKe
|
||||
}
|
||||
|
||||
// AES CTR
|
||||
void CryptoMbedTLS::aesCTRXcrypt(const std::vector<uint8_t> &key, std::vector<uint8_t> &iv, std::vector<uint8_t> &data)
|
||||
void CryptoMbedTLS::aesCTRXcrypt(const std::vector<uint8_t> &key, std::vector<uint8_t> &iv, uint8_t* buffer, size_t nbytes)
|
||||
{
|
||||
// needed for internal cache
|
||||
size_t off = 0;
|
||||
@@ -99,12 +99,12 @@ void CryptoMbedTLS::aesCTRXcrypt(const std::vector<uint8_t> &key, std::vector<ui
|
||||
|
||||
// Perform decrypt
|
||||
mbedtls_aes_crypt_ctr(&aesCtx,
|
||||
data.size(),
|
||||
nbytes,
|
||||
&off,
|
||||
iv.data(),
|
||||
streamBlock,
|
||||
data.data(),
|
||||
data.data());
|
||||
buffer,
|
||||
buffer);
|
||||
}
|
||||
|
||||
void CryptoMbedTLS::aesECBdecrypt(const std::vector<uint8_t> &key, std::vector<uint8_t> &data)
|
||||
@@ -115,7 +115,7 @@ void CryptoMbedTLS::aesECBdecrypt(const std::vector<uint8_t> &key, std::vector<u
|
||||
// Mbedtls's decrypt only works on 16 byte blocks
|
||||
for (unsigned int x = 0; x < data.size() / 16; x++)
|
||||
{
|
||||
// Perform decrypt
|
||||
// Perform finalize
|
||||
mbedtls_aes_crypt_ecb(&aesCtx,
|
||||
MBEDTLS_AES_DECRYPT,
|
||||
data.data() + (x * 16),
|
||||
|
||||
@@ -99,7 +99,7 @@ std::vector<uint8_t> CryptoOpenSSL::sha1HMAC(const std::vector<uint8_t>& inputKe
|
||||
}
|
||||
|
||||
// AES CTR
|
||||
void CryptoOpenSSL::aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, std::vector<uint8_t> &data)
|
||||
void CryptoOpenSSL::aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& iv, uint8_t* buffer, size_t nbytes)
|
||||
{
|
||||
// Prepare AES_KEY
|
||||
auto cryptoKey = AES_KEY();
|
||||
@@ -110,9 +110,9 @@ void CryptoOpenSSL::aesCTRXcrypt(const std::vector<uint8_t>& key, std::vector<ui
|
||||
unsigned int offsetInBlock = 0;
|
||||
|
||||
CRYPTO_ctr128_encrypt(
|
||||
data.data(),
|
||||
data.data(),
|
||||
data.size(),
|
||||
buffer,
|
||||
buffer,
|
||||
nbytes,
|
||||
&cryptoKey,
|
||||
iv.data(),
|
||||
ecountBuf,
|
||||
|
||||
@@ -287,7 +287,7 @@ std::string HTTPClient::HTTPResponse::readToString() {
|
||||
return result;
|
||||
}
|
||||
std::string result;
|
||||
char buffer[BUF_SIZE];
|
||||
char buffer[BUF_SIZE+1]; // make space for null-terminator
|
||||
size_t len;
|
||||
do {
|
||||
len = this->read(buffer, BUF_SIZE);
|
||||
|
||||
@@ -47,6 +47,22 @@ pb_bytes_array_t* vectorToPbArray(const std::vector<uint8_t>& vectorToPack)
|
||||
return result;
|
||||
}
|
||||
|
||||
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 pbPutBytes(const std::vector<uint8_t> &data, pb_bytes_array_t &dst) {
|
||||
dst.size = data.size();
|
||||
std::copy(data.begin(), data.end(), dst.bytes);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> pbArrayToVector(pb_bytes_array_t* pbArray) {
|
||||
return std::vector<uint8_t>(pbArray->bytes, pbArray->bytes + pbArray->size);
|
||||
}
|
||||
|
||||
@@ -14,12 +14,15 @@ class AudioChunk {
|
||||
private:
|
||||
/**
|
||||
* @brief Calculates a correct IV by performing bignum addition.
|
||||
*
|
||||
*
|
||||
* @param num Number to add to IV.
|
||||
* @return std::vector<uint8_t>
|
||||
* @return std::vector<uint8_t>
|
||||
*/
|
||||
std::vector<uint8_t> getIVSum(uint32_t num);
|
||||
|
||||
size_t decryptedCount = 0;
|
||||
size_t oldStartPos;
|
||||
|
||||
public:
|
||||
std::unique_ptr<Crypto> crypto;
|
||||
std::vector<uint8_t> decryptedData;
|
||||
@@ -41,14 +44,21 @@ public:
|
||||
std::unique_ptr<WrappedSemaphore> isLoadedSemaphore;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @brief
|
||||
*/
|
||||
std::unique_ptr<WrappedSemaphore> isHeaderFileSizeLoadedSemaphore;
|
||||
|
||||
/**
|
||||
* Decrypts data and writes it to the target buffer
|
||||
* @param target data buffer to write to
|
||||
* @param offset data offset
|
||||
* @param nbytes number of bytes to read
|
||||
*/
|
||||
void readData(uint8_t *target, size_t offset, size_t nbytes);
|
||||
|
||||
/**
|
||||
* @brief AudioChunk handles all audiochunk related operations.
|
||||
*
|
||||
*
|
||||
* @param seqId Sequence id of requested chunk
|
||||
* @param audioKey Audio key used for decryption of audio data
|
||||
* @param startPosition Start position of current chunk in audio file
|
||||
@@ -59,16 +69,16 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Appends incoming chunked data to local cache.
|
||||
*
|
||||
*
|
||||
* @param data encrypted binary audio data.
|
||||
*/
|
||||
void appendData(const std::vector<uint8_t> &data);
|
||||
|
||||
/**
|
||||
* @brief Performs AES CTR decryption of received data.
|
||||
*
|
||||
* @brief Sets loaded status on the chunk
|
||||
*
|
||||
*/
|
||||
void decrypt();
|
||||
void finalize();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,7 @@ class Packet
|
||||
private:
|
||||
|
||||
public:
|
||||
Packet(uint8_t command, std::vector<uint8_t> &data);
|
||||
Packet(uint8_t command, const std::vector<uint8_t> &data);
|
||||
uint8_t command;
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
void stream(std::vector<uint8_t> &buf); /* stream cipher */
|
||||
void maconly(std::vector<uint8_t> &buf); /* accumulate MAC */
|
||||
void encrypt(std::vector<uint8_t> &buf); /* encrypt + MAC */
|
||||
void decrypt(std::vector<uint8_t> &buf); /* decrypt + MAC */
|
||||
void decrypt(std::vector<uint8_t> &buf); /* finalize + MAC */
|
||||
void finish(std::vector<uint8_t> &buf); /* finalise MAC */
|
||||
|
||||
private:
|
||||
|
||||
@@ -37,6 +37,7 @@ class SpircController {
|
||||
private:
|
||||
std::shared_ptr<MercuryManager> manager;
|
||||
std::string username;
|
||||
bool firstFrame = true;
|
||||
std::unique_ptr<Player> player;
|
||||
std::unique_ptr<PlayerState> state;
|
||||
std::shared_ptr<AudioSink> audioSink;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
LoginCredentials.username type:FT_POINTER
|
||||
LoginCredentials.auth_data type:FT_POINTER
|
||||
LoginCredentials.auth_data type:FT_POINTER
|
||||
SystemInfo.system_information_string type:FT_POINTER
|
||||
SystemInfo.device_id type:FT_POINTER
|
||||
ClientResponseEncrypted.version_string type:FT_POINTER
|
||||
LoginCredentials.username max_size:30, fixed_length:false
|
||||
LoginCredentials.auth_data max_size:512, fixed_length:false
|
||||
SystemInfo.system_information_string max_size:16, fixed_length:false
|
||||
SystemInfo.device_id max_size:50, fixed_length:false
|
||||
ClientResponseEncrypted.version_string max_size:32, fixed_length:false
|
||||
@@ -9,7 +9,7 @@
|
||||
PB_BIND(SystemInfo, SystemInfo, 2)
|
||||
|
||||
|
||||
PB_BIND(LoginCredentials, LoginCredentials, AUTO)
|
||||
PB_BIND(LoginCredentials, LoginCredentials, 2)
|
||||
|
||||
|
||||
PB_BIND(ClientResponseEncrypted, ClientResponseEncrypted, 2)
|
||||
|
||||
@@ -58,23 +58,25 @@ typedef enum _AuthenticationType {
|
||||
} AuthenticationType;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef PB_BYTES_ARRAY_T(512) LoginCredentials_auth_data_t;
|
||||
typedef struct _LoginCredentials {
|
||||
char *username;
|
||||
char username[30];
|
||||
AuthenticationType typ;
|
||||
pb_bytes_array_t *auth_data;
|
||||
LoginCredentials_auth_data_t auth_data;
|
||||
} LoginCredentials;
|
||||
|
||||
typedef struct _SystemInfo {
|
||||
CpuFamily cpu_family;
|
||||
Os os;
|
||||
char *system_information_string;
|
||||
char *device_id;
|
||||
char system_information_string[16];
|
||||
char device_id[50];
|
||||
} SystemInfo;
|
||||
|
||||
typedef struct _ClientResponseEncrypted {
|
||||
LoginCredentials login_credentials;
|
||||
SystemInfo system_info;
|
||||
char *version_string;
|
||||
bool has_version_string;
|
||||
char version_string[32];
|
||||
} ClientResponseEncrypted;
|
||||
|
||||
|
||||
@@ -97,12 +99,12 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define SystemInfo_init_default {_CpuFamily_MIN, _Os_MIN, NULL, NULL}
|
||||
#define LoginCredentials_init_default {NULL, _AuthenticationType_MIN, NULL}
|
||||
#define ClientResponseEncrypted_init_default {LoginCredentials_init_default, SystemInfo_init_default, NULL}
|
||||
#define SystemInfo_init_zero {_CpuFamily_MIN, _Os_MIN, NULL, NULL}
|
||||
#define LoginCredentials_init_zero {NULL, _AuthenticationType_MIN, NULL}
|
||||
#define ClientResponseEncrypted_init_zero {LoginCredentials_init_zero, SystemInfo_init_zero, NULL}
|
||||
#define SystemInfo_init_default {_CpuFamily_MIN, _Os_MIN, "", ""}
|
||||
#define LoginCredentials_init_default {"", _AuthenticationType_MIN, {0, {0}}}
|
||||
#define ClientResponseEncrypted_init_default {LoginCredentials_init_default, SystemInfo_init_default, false, ""}
|
||||
#define SystemInfo_init_zero {_CpuFamily_MIN, _Os_MIN, "", ""}
|
||||
#define LoginCredentials_init_zero {"", _AuthenticationType_MIN, {0, {0}}}
|
||||
#define ClientResponseEncrypted_init_zero {LoginCredentials_init_zero, SystemInfo_init_zero, false, ""}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define LoginCredentials_username_tag 10
|
||||
@@ -120,22 +122,22 @@ extern "C" {
|
||||
#define SystemInfo_FIELDLIST(X, a) \
|
||||
X(a, STATIC, REQUIRED, UENUM, cpu_family, 10) \
|
||||
X(a, STATIC, REQUIRED, UENUM, os, 60) \
|
||||
X(a, POINTER, OPTIONAL, STRING, system_information_string, 90) \
|
||||
X(a, POINTER, OPTIONAL, STRING, device_id, 100)
|
||||
X(a, STATIC, REQUIRED, STRING, system_information_string, 90) \
|
||||
X(a, STATIC, REQUIRED, STRING, device_id, 100)
|
||||
#define SystemInfo_CALLBACK NULL
|
||||
#define SystemInfo_DEFAULT NULL
|
||||
|
||||
#define LoginCredentials_FIELDLIST(X, a) \
|
||||
X(a, POINTER, OPTIONAL, STRING, username, 10) \
|
||||
X(a, STATIC, REQUIRED, STRING, username, 10) \
|
||||
X(a, STATIC, REQUIRED, UENUM, typ, 20) \
|
||||
X(a, POINTER, OPTIONAL, BYTES, auth_data, 30)
|
||||
X(a, STATIC, REQUIRED, BYTES, auth_data, 30)
|
||||
#define LoginCredentials_CALLBACK NULL
|
||||
#define LoginCredentials_DEFAULT NULL
|
||||
|
||||
#define ClientResponseEncrypted_FIELDLIST(X, a) \
|
||||
X(a, STATIC, REQUIRED, MESSAGE, login_credentials, 10) \
|
||||
X(a, STATIC, REQUIRED, MESSAGE, system_info, 50) \
|
||||
X(a, POINTER, OPTIONAL, STRING, version_string, 70)
|
||||
X(a, STATIC, OPTIONAL, STRING, version_string, 70)
|
||||
#define ClientResponseEncrypted_CALLBACK NULL
|
||||
#define ClientResponseEncrypted_DEFAULT NULL
|
||||
#define ClientResponseEncrypted_login_credentials_MSGTYPE LoginCredentials
|
||||
@@ -151,9 +153,9 @@ extern const pb_msgdesc_t ClientResponseEncrypted_msg;
|
||||
#define ClientResponseEncrypted_fields &ClientResponseEncrypted_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* SystemInfo_size depends on runtime parameters */
|
||||
/* LoginCredentials_size depends on runtime parameters */
|
||||
/* ClientResponseEncrypted_size depends on runtime parameters */
|
||||
#define ClientResponseEncrypted_size 665
|
||||
#define LoginCredentials_size 550
|
||||
#define SystemInfo_size 75
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -48,14 +48,14 @@ enum AuthenticationType {
|
||||
message SystemInfo {
|
||||
required CpuFamily cpu_family = 0xa;
|
||||
required Os os = 0x3c;
|
||||
optional string system_information_string = 0x5a;
|
||||
optional string device_id = 0x64;
|
||||
required string system_information_string = 0x5a;
|
||||
required string device_id = 0x64;
|
||||
}
|
||||
|
||||
message LoginCredentials {
|
||||
optional string username = 0xa;
|
||||
required string username = 0xa;
|
||||
required AuthenticationType typ = 0x14;
|
||||
optional bytes auth_data = 0x1e;
|
||||
required bytes auth_data = 0x1e;
|
||||
}
|
||||
|
||||
message ClientResponseEncrypted {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Header.uri type:FT_POINTER
|
||||
Header.method type:FT_POINTER
|
||||
Header.uri max_size:64, fixed_length:false
|
||||
Header.method max_size:32, fixed_length:false
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _Header {
|
||||
char *uri;
|
||||
char *method;
|
||||
bool has_uri;
|
||||
char uri[64];
|
||||
bool has_method;
|
||||
char method[32];
|
||||
} Header;
|
||||
|
||||
|
||||
@@ -21,8 +23,8 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define Header_init_default {NULL, NULL}
|
||||
#define Header_init_zero {NULL, NULL}
|
||||
#define Header_init_default {false, "", false, ""}
|
||||
#define Header_init_zero {false, "", false, ""}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define Header_uri_tag 1
|
||||
@@ -30,8 +32,8 @@ extern "C" {
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define Header_FIELDLIST(X, a) \
|
||||
X(a, POINTER, OPTIONAL, STRING, uri, 1) \
|
||||
X(a, POINTER, OPTIONAL, STRING, method, 3)
|
||||
X(a, STATIC, OPTIONAL, STRING, uri, 1) \
|
||||
X(a, STATIC, OPTIONAL, STRING, method, 3)
|
||||
#define Header_CALLBACK NULL
|
||||
#define Header_DEFAULT NULL
|
||||
|
||||
@@ -41,7 +43,7 @@ extern const pb_msgdesc_t Header_msg;
|
||||
#define Header_fields &Header_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* Header_size depends on runtime parameters */
|
||||
#define Header_size 98
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
Track.name type:FT_POINTER
|
||||
Track.gid type:FT_POINTER
|
||||
Track.restriction type:FT_POINTER
|
||||
Track.alternative type:FT_POINTER
|
||||
Track.file type:FT_POINTER
|
||||
Track.artist type:FT_POINTER
|
||||
AudioFile.file_id type:FT_POINTER
|
||||
Image.file_id type:FT_POINTER
|
||||
Artist.gid type:FT_POINTER
|
||||
Artist.name type:FT_POINTER
|
||||
Album.name type:FT_POINTER
|
||||
Episode.gid type:FT_POINTER
|
||||
Episode.name type:FT_POINTER
|
||||
ImageGroup.image type:FT_POINTER
|
||||
Episode.audio type:FT_POINTER
|
||||
Episode.covers type:FT_POINTER
|
||||
Restriction.countries_allowed type:FT_POINTER
|
||||
Restriction.countries_forbidden type:FT_POINTER
|
||||
Track.name type: FT_POINTER
|
||||
Track.gid type: FT_POINTER
|
||||
Track.file type: FT_POINTER
|
||||
Track.restriction type: FT_POINTER
|
||||
Track.alternative type: FT_POINTER
|
||||
Track.artist type: FT_POINTER
|
||||
AudioFile.file_id type: FT_POINTER
|
||||
Image.file_id type: FT_POINTER
|
||||
Artist.gid type: FT_POINTER
|
||||
Artist.name type: FT_POINTER
|
||||
Album.name type: FT_POINTER
|
||||
Episode.gid type: FT_POINTER
|
||||
Episode.name type: FT_POINTER
|
||||
ImageGroup.image type: FT_POINTER
|
||||
Episode.audio type: FT_POINTER
|
||||
Episode.covers type: FT_POINTER
|
||||
Restriction.countries_allowed type: FT_POINTER
|
||||
Restriction.countries_forbidden type: FT_POINTER
|
||||
@@ -7,7 +7,7 @@ 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 max_count:100, fixed_count:false
|
||||
State.track type:FT_POINTER
|
||||
TrackRef.gid type:FT_POINTER
|
||||
TrackRef.uri type:FT_POINTER
|
||||
TrackRef.context type:FT_POINTER
|
||||
@@ -9,7 +9,7 @@
|
||||
PB_BIND(TrackRef, TrackRef, AUTO)
|
||||
|
||||
|
||||
PB_BIND(State, State, 4)
|
||||
PB_BIND(State, State, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Capability, Capability, 2)
|
||||
|
||||
@@ -62,6 +62,27 @@ typedef struct _Capability {
|
||||
char stringValue[50][50];
|
||||
} Capability;
|
||||
|
||||
typedef struct _State {
|
||||
char *context_uri;
|
||||
bool has_index;
|
||||
uint32_t index;
|
||||
bool has_position_ms;
|
||||
uint32_t position_ms;
|
||||
bool has_status;
|
||||
PlayStatus status;
|
||||
bool has_position_measured_at;
|
||||
uint64_t position_measured_at;
|
||||
pb_callback_t context_description;
|
||||
bool has_shuffle;
|
||||
bool shuffle;
|
||||
bool has_repeat;
|
||||
bool repeat;
|
||||
bool has_playing_track_index;
|
||||
uint32_t playing_track_index;
|
||||
pb_size_t track_count;
|
||||
struct _TrackRef *track;
|
||||
} State;
|
||||
|
||||
typedef struct _TrackRef {
|
||||
pb_bytes_array_t *gid;
|
||||
char *uri;
|
||||
@@ -89,27 +110,6 @@ typedef struct _DeviceState {
|
||||
pb_callback_t local_uris;
|
||||
} DeviceState;
|
||||
|
||||
typedef struct _State {
|
||||
char *context_uri;
|
||||
bool has_index;
|
||||
uint32_t index;
|
||||
bool has_position_ms;
|
||||
uint32_t position_ms;
|
||||
bool has_status;
|
||||
PlayStatus status;
|
||||
bool has_position_measured_at;
|
||||
uint64_t position_measured_at;
|
||||
pb_callback_t context_description;
|
||||
bool has_shuffle;
|
||||
bool shuffle;
|
||||
bool has_repeat;
|
||||
bool repeat;
|
||||
bool has_playing_track_index;
|
||||
uint32_t playing_track_index;
|
||||
pb_size_t track_count;
|
||||
TrackRef track[100];
|
||||
} State;
|
||||
|
||||
typedef struct _Frame {
|
||||
bool has_version;
|
||||
uint32_t version;
|
||||
@@ -154,12 +154,12 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define TrackRef_init_default {NULL, NULL, false, 0, NULL}
|
||||
#define State_init_default {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default}}
|
||||
#define State_init_default {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, NULL}
|
||||
#define Capability_init_default {false, _CapabilityType_MIN, 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, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}}
|
||||
#define DeviceState_init_default {NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default}, {{NULL}, NULL}}
|
||||
#define Frame_init_default {false, 0, NULL, NULL, false, 0, false, _MessageType_MIN, false, DeviceState_init_default, false, State_init_default, false, 0, false, 0, false, 0, 0, NULL}
|
||||
#define TrackRef_init_zero {NULL, NULL, false, 0, NULL}
|
||||
#define State_init_zero {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero}}
|
||||
#define State_init_zero {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, NULL}
|
||||
#define Capability_init_zero {false, _CapabilityType_MIN, 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, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}}
|
||||
#define DeviceState_init_zero {NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero}, {{NULL}, NULL}}
|
||||
#define Frame_init_zero {false, 0, NULL, NULL, false, 0, false, _MessageType_MIN, false, DeviceState_init_zero, false, State_init_zero, false, 0, false, 0, false, 0, 0, NULL}
|
||||
@@ -168,6 +168,16 @@ extern "C" {
|
||||
#define Capability_typ_tag 1
|
||||
#define Capability_intValue_tag 2
|
||||
#define Capability_stringValue_tag 3
|
||||
#define State_context_uri_tag 2
|
||||
#define State_index_tag 3
|
||||
#define State_position_ms_tag 4
|
||||
#define State_status_tag 5
|
||||
#define State_position_measured_at_tag 7
|
||||
#define State_context_description_tag 8
|
||||
#define State_shuffle_tag 13
|
||||
#define State_repeat_tag 14
|
||||
#define State_playing_track_index_tag 26
|
||||
#define State_track_tag 27
|
||||
#define TrackRef_gid_tag 1
|
||||
#define TrackRef_uri_tag 2
|
||||
#define TrackRef_queued_tag 3
|
||||
@@ -182,16 +192,6 @@ extern "C" {
|
||||
#define DeviceState_error_message_tag 16
|
||||
#define DeviceState_capabilities_tag 17
|
||||
#define DeviceState_local_uris_tag 18
|
||||
#define State_context_uri_tag 2
|
||||
#define State_index_tag 3
|
||||
#define State_position_ms_tag 4
|
||||
#define State_status_tag 5
|
||||
#define State_position_measured_at_tag 7
|
||||
#define State_context_description_tag 8
|
||||
#define State_shuffle_tag 13
|
||||
#define State_repeat_tag 14
|
||||
#define State_playing_track_index_tag 26
|
||||
#define State_track_tag 27
|
||||
#define Frame_version_tag 1
|
||||
#define Frame_ident_tag 2
|
||||
#define Frame_protocol_version_tag 3
|
||||
@@ -223,7 +223,7 @@ X(a, CALLBACK, OPTIONAL, STRING, context_description, 8) \
|
||||
X(a, STATIC, OPTIONAL, BOOL, shuffle, 13) \
|
||||
X(a, STATIC, OPTIONAL, BOOL, repeat, 14) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, playing_track_index, 26) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, track, 27)
|
||||
X(a, POINTER, REPEATED, MESSAGE, track, 27)
|
||||
#define State_CALLBACK pb_default_field_callback
|
||||
#define State_DEFAULT NULL
|
||||
#define State_track_MSGTYPE TrackRef
|
||||
|
||||
@@ -24,13 +24,28 @@ void AudioChunk::appendData(const std::vector<uint8_t> &data)
|
||||
this->decryptedData.insert(this->decryptedData.end(), data.begin(), data.end());
|
||||
}
|
||||
|
||||
void AudioChunk::decrypt()
|
||||
void AudioChunk::readData(uint8_t *target, size_t offset, size_t nbytes) {
|
||||
auto readPos = offset + nbytes;
|
||||
auto modulo = (readPos % 16);
|
||||
auto ivReadPos = readPos;
|
||||
if (modulo != 0) {
|
||||
ivReadPos += (16 - modulo);
|
||||
}
|
||||
if (ivReadPos > decryptedCount) {
|
||||
// calculate the IV for right position
|
||||
auto calculatedIV = this->getIVSum((oldStartPos + decryptedCount) / 16);
|
||||
|
||||
crypto->aesCTRXcrypt(this->audioKey, calculatedIV, decryptedData.data() + decryptedCount, ivReadPos - decryptedCount);
|
||||
|
||||
decryptedCount = ivReadPos;
|
||||
}
|
||||
memcpy(target, this->decryptedData.data() + offset, nbytes);
|
||||
|
||||
}
|
||||
|
||||
void AudioChunk::finalize()
|
||||
{
|
||||
// calculate the IV for right position
|
||||
auto calculatedIV = this->getIVSum(startPosition / 16);
|
||||
|
||||
crypto->aesCTRXcrypt(this->audioKey, calculatedIV, decryptedData);
|
||||
|
||||
this->oldStartPos = this->startPosition;
|
||||
this->startPosition = this->endPosition - this->decryptedData.size();
|
||||
this->isLoaded = true;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "Logger.h"
|
||||
|
||||
AudioChunkManager::AudioChunkManager()
|
||||
: bell::Task("AudioChunkManager", 4 * 1024, 2, 0) {
|
||||
: bell::Task("AudioChunkManager", 4 * 1024, -1, 0) {
|
||||
this->chunks = std::vector<std::shared_ptr<AudioChunk>>();
|
||||
startTask();
|
||||
}
|
||||
@@ -80,7 +80,7 @@ void AudioChunkManager::runTask() {
|
||||
|
||||
switch (data.size()) {
|
||||
case DATA_SIZE_HEADER: {
|
||||
CSPOT_LOG(debug, "ID: %d: header decrypt!", seqId);
|
||||
CSPOT_LOG(debug, "ID: %d: header finalize!", seqId);
|
||||
auto headerSize = ntohs(extract<uint16_t>(data, 2));
|
||||
// Got file size!
|
||||
chunk->headerFileSize =
|
||||
@@ -92,9 +92,9 @@ void AudioChunkManager::runTask() {
|
||||
if (chunk->endPosition > chunk->headerFileSize) {
|
||||
chunk->endPosition = chunk->headerFileSize;
|
||||
}
|
||||
CSPOT_LOG(debug, "ID: %d: Starting decrypt!",
|
||||
CSPOT_LOG(debug, "ID: %d: finalize chunk!",
|
||||
seqId);
|
||||
chunk->decrypt();
|
||||
chunk->finalize();
|
||||
chunk->isLoadedSemaphore->give();
|
||||
break;
|
||||
|
||||
|
||||
@@ -156,7 +156,6 @@ void ChunkedAudioStream::startPlaybackLoop()
|
||||
|
||||
void ChunkedAudioStream::seek(size_t dpos, Whence whence)
|
||||
{
|
||||
BELL_LOG(info, "cspot", "%d", dpos);
|
||||
auto seekPos = 0;
|
||||
switch (whence)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ void ChunkedByteStream::fetchFileInformation() {
|
||||
endChunk->keepInMemory = true;
|
||||
|
||||
chunks.push_back(endChunk);
|
||||
requestChunk(0);
|
||||
}
|
||||
|
||||
std::shared_ptr<AudioChunk> ChunkedByteStream::getChunkForPosition(size_t position) {
|
||||
@@ -57,11 +58,14 @@ size_t ChunkedByteStream::read(uint8_t *buf, size_t nbytes) {
|
||||
std::scoped_lock lock(this->readMutex);
|
||||
auto chunk = getChunkForPosition(pos);
|
||||
uint16_t chunkIndex = this->pos / AUDIO_CHUNK_SIZE;
|
||||
for (auto it = chunks.begin(); it != chunks.end();) {
|
||||
if (((*it)->endPosition<pos || (*it)->startPosition>(pos + 2 * AUDIO_CHUNK_SIZE)) && !(*it)->keepInMemory) {
|
||||
it = chunks.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
|
||||
if (loadAheadEnabled) {
|
||||
for (auto it = chunks.begin(); it != chunks.end();) {
|
||||
if (((*it)->endPosition<pos || (*it)->startPosition>(pos + 2 * AUDIO_CHUNK_SIZE)) && !(*it)->keepInMemory) {
|
||||
it = chunks.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +89,7 @@ size_t ChunkedByteStream::read(uint8_t *buf, size_t nbytes) {
|
||||
pos += read;
|
||||
|
||||
auto nextChunkPos = ((chunkIndex + 1) * AUDIO_CHUNK_SIZE) + 1;
|
||||
if (loadAheadEnabled && nextChunkPos + AUDIO_CHUNK_SIZE < fileSize) {
|
||||
if (loadAheadEnabled && nextChunkPos < fileSize) {
|
||||
auto nextChunk = getChunkForPosition(nextChunkPos);
|
||||
|
||||
if (nextChunk == nullptr) {
|
||||
@@ -109,15 +113,12 @@ size_t ChunkedByteStream::attemptRead(uint8_t *buffer, size_t bytes, std::shared
|
||||
toRead = chunk->decryptedData.size() - offset;
|
||||
}
|
||||
|
||||
// Copy data
|
||||
memcpy(buffer, chunk->decryptedData.data() + offset, toRead);
|
||||
|
||||
chunk->readData(buffer, offset, toRead);
|
||||
return toRead;
|
||||
}
|
||||
|
||||
void ChunkedByteStream::seek(size_t nbytes) {
|
||||
std::scoped_lock lock(this->readMutex);
|
||||
BELL_LOG(info, "cspot", "seeking to %d", nbytes);
|
||||
pos = nbytes;
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ std::vector<uint8_t> LoginBlob::decodeBlob(const std::vector<uint8_t> &blob, con
|
||||
}
|
||||
|
||||
encryptionKey = std::vector<uint8_t>(encryptionKey.begin(), encryptionKey.begin() + 16);
|
||||
crypto->aesCTRXcrypt(encryptionKey, iv, encrypted);
|
||||
crypto->aesCTRXcrypt(encryptionKey, iv, encrypted.data(), encrypted.size());
|
||||
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ std::map<MercuryType, std::string> MercuryTypeMap({
|
||||
{MercuryType::UNSUB, "UNSUB"},
|
||||
});
|
||||
|
||||
MercuryManager::MercuryManager(std::unique_ptr<Session> session): bell::Task("mercuryManager", 6 * 1024, 2, 1)
|
||||
MercuryManager::MercuryManager(std::unique_ptr<Session> session): bell::Task("mercuryManager", 6 * 1024, 0, 1)
|
||||
{
|
||||
tempMercuryHeader = Header_init_default;
|
||||
tempMercuryHeader = {};
|
||||
this->timeProvider = std::make_shared<TimeProvider>();
|
||||
this->callbacks = std::map<uint64_t, mercuryCallback>();
|
||||
this->subscriptions = std::map<std::string, mercuryCallback>();
|
||||
@@ -294,8 +294,11 @@ uint64_t MercuryManager::execute(MercuryType method, std::string uri, mercuryCal
|
||||
// Construct mercury header
|
||||
|
||||
CSPOT_LOG(debug, "executing MercuryType %s", MercuryTypeMap[method].c_str());
|
||||
tempMercuryHeader.uri = (char *)(uri.c_str());
|
||||
tempMercuryHeader.method = (char *)(MercuryTypeMap[method].c_str());
|
||||
pbPutString(uri, tempMercuryHeader.uri);
|
||||
pbPutString(MercuryTypeMap[method], tempMercuryHeader.method);
|
||||
|
||||
tempMercuryHeader.has_method = true;
|
||||
tempMercuryHeader.has_uri = true;
|
||||
|
||||
// GET and SEND are actually the same. Therefore the override
|
||||
// The difference between them is only in header's method
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
MercuryResponse::MercuryResponse(std::vector<uint8_t> &data)
|
||||
{
|
||||
// this->mercuryHeader = std::make_unique<Header>();
|
||||
this->mercuryHeader = Header_init_default;
|
||||
this->mercuryHeader = {};
|
||||
this->parts = mercuryParts(0);
|
||||
this->parseResponse(data);
|
||||
}
|
||||
|
||||
MercuryResponse::~MercuryResponse() {
|
||||
pb_release(Header_fields, &mercuryHeader);
|
||||
}
|
||||
|
||||
void MercuryResponse::parseResponse(std::vector<uint8_t> &data)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "Packet.h"
|
||||
|
||||
Packet::Packet(uint8_t command, std::vector<uint8_t> &data) {
|
||||
Packet::Packet(uint8_t command, const std::vector<uint8_t> &data) {
|
||||
this->command = command;
|
||||
this->data = data;
|
||||
};
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// #include <valgrind/memcheck.h>
|
||||
|
||||
Player::Player(std::shared_ptr<MercuryManager> manager, std::shared_ptr<AudioSink> audioSink): bell::Task("player", 10 * 1024, +0, 1)
|
||||
Player::Player(std::shared_ptr<MercuryManager> manager, std::shared_ptr<AudioSink> audioSink): bell::Task("player", 10 * 1024, -2, 1)
|
||||
{
|
||||
this->audioSink = audioSink;
|
||||
this->manager = manager;
|
||||
|
||||
@@ -24,18 +24,18 @@ PlayerState::PlayerState(std::shared_ptr<TimeProvider> timeProvider)
|
||||
innerFrame.state.repeat = false;
|
||||
innerFrame.state.has_repeat = true;
|
||||
|
||||
innerFrame.device_state.sw_version = (char*) swVersion;
|
||||
innerFrame.device_state.sw_version = strdup(swVersion);
|
||||
|
||||
innerFrame.device_state.is_active = false;
|
||||
innerFrame.device_state.has_is_active = true;
|
||||
|
||||
|
||||
innerFrame.device_state.can_play = true;
|
||||
innerFrame.device_state.has_can_play = true;
|
||||
|
||||
innerFrame.device_state.volume = configMan->volume;
|
||||
innerFrame.device_state.has_volume = true;
|
||||
|
||||
innerFrame.device_state.name = (char*) configMan->deviceName.c_str();
|
||||
innerFrame.device_state.name = strdup(configMan->deviceName.c_str());
|
||||
|
||||
// Prepare player's capabilities
|
||||
addCapability(CapabilityType_kCanBePlayer, 1);
|
||||
@@ -53,33 +53,32 @@ PlayerState::PlayerState(std::shared_ptr<TimeProvider> timeProvider)
|
||||
}
|
||||
|
||||
PlayerState::~PlayerState() {
|
||||
pb_release(Frame_fields, &innerFrame);
|
||||
pb_release(Frame_fields, &remoteFrame);
|
||||
// do not destruct inner frame as it is never allocated
|
||||
// pb_release(Frame_fields, &innerFrame);
|
||||
}
|
||||
|
||||
void PlayerState::setPlaybackState(const PlaybackState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case PlaybackState::Loading:
|
||||
// Prepare the playback at position 0
|
||||
innerFrame.state.status = PlayStatus_kPlayStatusPause;
|
||||
innerFrame.state.position_ms = 0;
|
||||
innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
|
||||
break;
|
||||
case PlaybackState::Playing:
|
||||
innerFrame.state.status = PlayStatus_kPlayStatusPlay;
|
||||
innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
|
||||
break;
|
||||
case PlaybackState::Stopped:
|
||||
break;
|
||||
case PlaybackState::Paused:
|
||||
// Update state and recalculate current song position
|
||||
innerFrame.state.status = PlayStatus_kPlayStatusPause;
|
||||
uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state.position_measured_at;
|
||||
this->updatePositionMs(innerFrame.state.position_ms + diff);
|
||||
break;
|
||||
case PlaybackState::Loading:
|
||||
// Prepare the playback at position 0
|
||||
innerFrame.state.status = PlayStatus_kPlayStatusPause;
|
||||
innerFrame.state.position_ms = 0;
|
||||
innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
|
||||
break;
|
||||
case PlaybackState::Playing:
|
||||
innerFrame.state.status = PlayStatus_kPlayStatusPlay;
|
||||
innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
|
||||
break;
|
||||
case PlaybackState::Stopped:
|
||||
break;
|
||||
case PlaybackState::Paused:
|
||||
// Update state and recalculate current song position
|
||||
innerFrame.state.status = PlayStatus_kPlayStatusPause;
|
||||
uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state.position_measured_at;
|
||||
this->updatePositionMs(innerFrame.state.position_ms + diff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,8 +136,8 @@ void PlayerState::updatePositionMs(uint32_t position)
|
||||
void PlayerState::updateTracks()
|
||||
{
|
||||
CSPOT_LOG(info, "---- Track count %d", remoteFrame.state.track_count);
|
||||
//innerFrame.state.context_uri = remoteFrame.state.context_uri == nullptr ? nullptr : strdup(remoteFrame.state.context_uri);
|
||||
std::copy(std::begin(remoteFrame.state.track), std::end(remoteFrame.state.track), std::begin(innerFrame.state.track));
|
||||
std::swap(innerFrame.state.context_uri, remoteFrame.state.context_uri);
|
||||
std::swap(innerFrame.state.track, remoteFrame.state.track);
|
||||
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;
|
||||
@@ -167,17 +166,13 @@ void PlayerState::setShuffle(bool shuffle)
|
||||
if (shuffle)
|
||||
{
|
||||
// Put current song at the begining
|
||||
auto tmp = innerFrame.state.track[0];
|
||||
innerFrame.state.track[0] = innerFrame.state.track[innerFrame.state.playing_track_index];
|
||||
innerFrame.state.track[innerFrame.state.playing_track_index] = tmp;
|
||||
std::swap(innerFrame.state.track[0], innerFrame.state.track[innerFrame.state.playing_track_index]);
|
||||
|
||||
// Shuffle current tracks
|
||||
for (int x = 1; x < innerFrame.state.track_count - 1; x++)
|
||||
{
|
||||
auto j = x + (std::rand() % (innerFrame.state.track_count - x));
|
||||
tmp = innerFrame.state.track[j];
|
||||
innerFrame.state.track[j] = innerFrame.state.track[x];
|
||||
innerFrame.state.track[x] = tmp;
|
||||
std::swap(innerFrame.state.track[j], innerFrame.state.track[x]);
|
||||
}
|
||||
innerFrame.state.playing_track_index = 0;
|
||||
}
|
||||
@@ -196,11 +191,14 @@ std::shared_ptr<TrackReference> PlayerState::getCurrentTrack()
|
||||
|
||||
std::vector<uint8_t> PlayerState::encodeCurrentFrame(MessageType typ)
|
||||
{
|
||||
free(innerFrame.ident);
|
||||
free(innerFrame.protocol_version);
|
||||
|
||||
// Prepare current frame info
|
||||
innerFrame.version = 1;
|
||||
innerFrame.ident = (char *) deviceId;
|
||||
innerFrame.ident = strdup(deviceId);
|
||||
innerFrame.seq_nr = this->seqNum;
|
||||
innerFrame.protocol_version = (char*) protocolVersion;
|
||||
innerFrame.protocol_version = strdup(protocolVersion);
|
||||
innerFrame.typ = typ;
|
||||
innerFrame.state_update_id = timeProvider->getSyncedTimestamp();
|
||||
innerFrame.has_version = true;
|
||||
@@ -233,10 +231,9 @@ void PlayerState::addCapability(CapabilityType typ, int intValue, std::vector<st
|
||||
|
||||
for (int x = 0; x < stringValue.size(); x++)
|
||||
{
|
||||
stringValue[x].copy(this->innerFrame.device_state.capabilities[capabilityIndex].stringValue[x], stringValue[x].size());
|
||||
this->innerFrame.device_state.capabilities[capabilityIndex].stringValue[x][stringValue[x].size()] = '\0';
|
||||
pbPutString(stringValue[x], this->innerFrame.device_state.capabilities[capabilityIndex].stringValue[x]);
|
||||
}
|
||||
|
||||
this->innerFrame.device_state.capabilities[capabilityIndex].stringValue_count = stringValue.size();
|
||||
this->capabilityIndex += 1;
|
||||
}
|
||||
}
|
||||
@@ -49,17 +49,26 @@ std::vector<uint8_t> Session::authenticate(std::shared_ptr<LoginBlob> blob)
|
||||
authBlob = blob;
|
||||
|
||||
// prepare authentication request proto
|
||||
authRequest.login_credentials.username = (char *)(blob->username.c_str());
|
||||
authRequest.login_credentials.auth_data = vectorToPbArray(blob->authData);
|
||||
pbPutString(blob->username, authRequest.login_credentials.username);
|
||||
|
||||
std::copy(blob->authData.begin(), blob->authData.end(), authRequest.login_credentials.auth_data.bytes);
|
||||
authRequest.login_credentials.auth_data.size = blob->authData.size();
|
||||
|
||||
authRequest.login_credentials.typ = (AuthenticationType) blob->authType;
|
||||
authRequest.system_info.cpu_family = CpuFamily_CPU_UNKNOWN;
|
||||
authRequest.system_info.os = Os_OS_UNKNOWN;
|
||||
authRequest.system_info.system_information_string = (char *)informationString;
|
||||
authRequest.system_info.device_id = (char *)deviceId;
|
||||
authRequest.version_string = (char *)versionString;
|
||||
|
||||
auto infoStr = std::string(informationString);
|
||||
pbPutString(infoStr, authRequest.system_info.system_information_string);
|
||||
|
||||
auto deviceIdStr = std::string(deviceId);
|
||||
pbPutString(deviceId, authRequest.system_info.device_id);
|
||||
|
||||
auto versionStr = std::string(versionString);
|
||||
pbPutString(versionStr, authRequest.version_string);
|
||||
authRequest.has_version_string = true;
|
||||
|
||||
auto data = pbEncode(ClientResponseEncrypted_fields, &authRequest);
|
||||
free(authRequest.login_credentials.auth_data);
|
||||
|
||||
// Send login request
|
||||
this->shanConn->sendPacket(LOGIN_REQUEST_COMMAND, data);
|
||||
|
||||
@@ -56,7 +56,7 @@ void SpircController::disconnect(void) {
|
||||
state->setActive(false);
|
||||
notify();
|
||||
// Send the event at the end at it might be a last gasp
|
||||
sendEvent(CSpotEventType::DISC);
|
||||
sendEvent(CSpotEventType::DISC);
|
||||
}
|
||||
|
||||
void SpircController::playToggle() {
|
||||
@@ -103,7 +103,7 @@ void SpircController::prevSong() {
|
||||
}
|
||||
|
||||
void SpircController::handleFrame(std::vector<uint8_t> &data) {
|
||||
//pb_release(Frame_fields, &state->remoteFrame);
|
||||
pb_release(Frame_fields, &state->remoteFrame);
|
||||
pbDecode(state->remoteFrame, Frame_fields, data);
|
||||
|
||||
switch (state->remoteFrame.typ) {
|
||||
|
||||
@@ -10,8 +10,8 @@ SpotifyTrack::SpotifyTrack(std::shared_ptr<MercuryManager> manager, std::shared_
|
||||
{
|
||||
this->manager = manager;
|
||||
this->fileId = std::vector<uint8_t>();
|
||||
episodeInfo = Episode_init_default;
|
||||
trackInfo = Track_init_default;
|
||||
episodeInfo = {};
|
||||
trackInfo = {};
|
||||
|
||||
mercuryCallback trackResponseLambda = [=](std::unique_ptr<MercuryResponse> res) {
|
||||
this->trackInformationCallback(std::move(res), position_ms, isPaused);
|
||||
@@ -84,13 +84,15 @@ void SpotifyTrack::trackInformationCallback(std::unique_ptr<MercuryResponse> res
|
||||
int altIndex = 0;
|
||||
while (!canPlayTrack())
|
||||
{
|
||||
trackInfo.restriction = trackInfo.alternative[altIndex].restriction;
|
||||
trackInfo.restriction_count = trackInfo.alternative[altIndex].restriction_count;
|
||||
trackInfo.gid = trackInfo.alternative[altIndex].gid;
|
||||
trackInfo.file = trackInfo.alternative[altIndex].file;
|
||||
altIndex++;
|
||||
std::swap(trackInfo.restriction, trackInfo.alternative[altIndex].restriction);
|
||||
std::swap(trackInfo.restriction_count, trackInfo.alternative[altIndex].restriction_count);
|
||||
std::swap(trackInfo.file, trackInfo.alternative[altIndex].file);
|
||||
std::swap(trackInfo.file_count, trackInfo.alternative[altIndex].file_count);
|
||||
std::swap(trackInfo.gid, trackInfo.alternative[altIndex].gid);
|
||||
|
||||
CSPOT_LOG(info, "Trying alternative %d", altIndex);
|
||||
}
|
||||
|
||||
auto trackId = pbArrayToVector(trackInfo.gid);
|
||||
this->fileId = std::vector<uint8_t>();
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "display.h"
|
||||
#include "accessors.h"
|
||||
#include "network_services.h"
|
||||
#include "tools.h"
|
||||
#include "cspot_private.h"
|
||||
#include "cspot_sink.h"
|
||||
|
||||
@@ -87,6 +88,19 @@ const static actrls_t controls = {
|
||||
cspot_volume_down, cspot_volume_up, cspot_toggle// knob left, knob_right, knob push
|
||||
};
|
||||
|
||||
/****************************************************************************************
|
||||
* Download callback
|
||||
*/
|
||||
void got_artwork(uint8_t* data, size_t len, void *context) {
|
||||
if (data) {
|
||||
ESP_LOGI(TAG, "got artwork of %zu bytes", len);
|
||||
displayer_artwork(data);
|
||||
free(data);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "artwork error or too large %zu", len);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* Command handler
|
||||
*/
|
||||
@@ -106,7 +120,7 @@ static bool cmd_handler(cspot_event_t event, ...) {
|
||||
switch(event) {
|
||||
case CSPOT_SETUP:
|
||||
actrls_set(controls, false, NULL, actrls_ir_action);
|
||||
displayer_control(DISPLAYER_ACTIVATE, "SPOTIFY");
|
||||
displayer_control(DISPLAYER_ACTIVATE, "SPOTIFY", true);
|
||||
break;
|
||||
case CSPOT_PLAY:
|
||||
displayer_control(DISPLAYER_TIMER_RUN);
|
||||
@@ -129,6 +143,11 @@ static bool cmd_handler(cspot_event_t event, ...) {
|
||||
uint32_t sample_rate = va_arg(args, uint32_t);
|
||||
int duration = va_arg(args, int);
|
||||
char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*);
|
||||
char *artwork = va_arg(args, char*);
|
||||
if (artwork && displayer_can_artwork()) {
|
||||
ESP_LOGI(TAG, "requesting artwork %s", artwork);
|
||||
http_download(artwork, 128*1024, got_artwork, NULL);
|
||||
}
|
||||
displayer_metadata(artist, album, title);
|
||||
displayer_timer(DISPLAYER_ELAPSED, loaded ? -1 : 0, duration);
|
||||
loaded = false;
|
||||
|
||||
Reference in New Issue
Block a user