mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 20:47:08 +03:00
135 lines
4.2 KiB
C++
135 lines
4.2 KiB
C++
#pragma once
|
|
|
|
#include <atomic> // for atomic
|
|
#include <cstdint> // for uint8_t, uint64_t, uint32_t
|
|
#include <functional> // for function
|
|
#include <memory> // for shared_ptr
|
|
#include <mutex> // for mutex
|
|
#include <string> // for string
|
|
#include <unordered_map> // for unordered_map
|
|
#include <vector> // for vector
|
|
|
|
#include "BellTask.h" // for Task
|
|
#include "Packet.h" // for Packet
|
|
#include "Queue.h" // for Queue
|
|
#include "Session.h" // for Session
|
|
#include "protobuf/mercury.pb.h" // for Header
|
|
|
|
namespace cspot {
|
|
class TimeProvider;
|
|
|
|
class MercurySession : public bell::Task, public cspot::Session {
|
|
public:
|
|
MercurySession(std::shared_ptr<cspot::TimeProvider> timeProvider);
|
|
~MercurySession();
|
|
typedef std::vector<std::vector<uint8_t>> DataParts;
|
|
|
|
struct Response {
|
|
Header mercuryHeader;
|
|
uint8_t flags;
|
|
DataParts parts;
|
|
uint64_t sequenceId;
|
|
bool fail;
|
|
};
|
|
|
|
typedef std::function<void(Response&)> ResponseCallback;
|
|
typedef std::function<void(bool, const std::vector<uint8_t>&)>
|
|
AudioKeyCallback;
|
|
typedef std::function<void()> ConnectionEstabilishedCallback;
|
|
|
|
enum class RequestType : uint8_t {
|
|
SUB = 0xb3,
|
|
UNSUB = 0xb4,
|
|
SUBRES = 0xb5,
|
|
SEND = 0xb2,
|
|
GET = 0xFF, // Shitty workaround, it's value is actually same as SEND
|
|
PING = 0x04,
|
|
PONG_ACK = 0x4a,
|
|
AUDIO_CHUNK_REQUEST_COMMAND = 0x08,
|
|
AUDIO_CHUNK_SUCCESS_RESPONSE = 0x09,
|
|
AUDIO_CHUNK_FAILURE_RESPONSE = 0x0A,
|
|
AUDIO_KEY_REQUEST_COMMAND = 0x0C,
|
|
AUDIO_KEY_SUCCESS_RESPONSE = 0x0D,
|
|
AUDIO_KEY_FAILURE_RESPONSE = 0x0E,
|
|
COUNTRY_CODE_RESPONSE = 0x1B,
|
|
};
|
|
|
|
std::unordered_map<RequestType, std::string> RequestTypeMap = {
|
|
{RequestType::GET, "GET"},
|
|
{RequestType::SEND, "SEND"},
|
|
{RequestType::SUB, "SUB"},
|
|
{RequestType::UNSUB, "UNSUB"},
|
|
};
|
|
|
|
void handlePacket();
|
|
|
|
uint64_t executeSubscription(RequestType type, const std::string& uri,
|
|
ResponseCallback callback,
|
|
ResponseCallback subscription, DataParts& parts);
|
|
uint64_t executeSubscription(RequestType type, const std::string& uri,
|
|
ResponseCallback callback,
|
|
ResponseCallback subscription) {
|
|
DataParts parts = {};
|
|
return this->executeSubscription(type, uri, callback, subscription, parts);
|
|
}
|
|
|
|
uint64_t execute(RequestType type, const std::string& uri,
|
|
ResponseCallback callback) {
|
|
return this->executeSubscription(type, uri, callback, nullptr);
|
|
}
|
|
|
|
uint64_t execute(RequestType type, const std::string& uri,
|
|
ResponseCallback callback, DataParts& parts) {
|
|
return this->executeSubscription(type, uri, callback, nullptr, parts);
|
|
}
|
|
|
|
void unregister(uint64_t sequenceId);
|
|
|
|
void unregisterAudioKey(uint32_t sequenceId);
|
|
|
|
uint32_t requestAudioKey(const std::vector<uint8_t>& trackId,
|
|
const std::vector<uint8_t>& fileId,
|
|
AudioKeyCallback audioCallback);
|
|
|
|
std::string getCountryCode();
|
|
|
|
void disconnect();
|
|
|
|
void setConnectedHandler(ConnectionEstabilishedCallback callback);
|
|
|
|
bool triggerTimeout() override;
|
|
|
|
private:
|
|
const int PING_TIMEOUT_MS = 2 * 60 * 1000 + 5000;
|
|
|
|
std::shared_ptr<cspot::TimeProvider> timeProvider;
|
|
Header tempMercuryHeader = {};
|
|
ConnectionEstabilishedCallback connectionReadyCallback = nullptr;
|
|
|
|
bell::Queue<cspot::Packet> packetQueue;
|
|
|
|
void runTask() override;
|
|
void reconnect();
|
|
|
|
std::unordered_map<uint64_t, ResponseCallback> callbacks;
|
|
std::unordered_map<std::string, ResponseCallback> subscriptions;
|
|
std::unordered_map<uint32_t, AudioKeyCallback> audioKeyCallbacks;
|
|
|
|
uint64_t sequenceId = 1;
|
|
uint32_t audioKeySequence = 1;
|
|
|
|
unsigned long long timestampDiff;
|
|
unsigned long long lastPingTimestamp = -1;
|
|
std::string countryCode = "";
|
|
|
|
std::mutex isRunningMutex;
|
|
std::atomic<bool> isRunning = false;
|
|
std::atomic<bool> isReconnecting = false;
|
|
std::atomic<bool> executeEstabilishedCallback = false;
|
|
|
|
void failAllPending();
|
|
|
|
Response decodeResponse(const std::vector<uint8_t>& data);
|
|
};
|
|
} // namespace cspot
|