update cspot

This commit is contained in:
philippe44
2022-11-17 14:06:00 -08:00
parent a81d0e0513
commit 7e5f27af12
137 changed files with 6046 additions and 836 deletions

View File

@@ -6,7 +6,14 @@
#include <map>
#include <memory>
#include <functional>
#include <iostream>
#include <vector>
#include <cstring>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
namespace bell {
@@ -20,6 +27,40 @@ class ResponseReader {
virtual void close() = 0;
};
class RequestBodyReader : public ResponseReader {
public:
std::vector<uint8_t> partialBuffer;
int fd = 0;
size_t contentLength = 0;
size_t sizeRead = 0;
RequestBodyReader(size_t contentLength, int fd, std::vector<uint8_t> &partialBuffer) {
this->contentLength = contentLength;
this->partialBuffer = partialBuffer;
this->fd = fd;
};
size_t read(char *buffer, size_t size) {
if (sizeRead < partialBuffer.size()) {
size_t toRead = std::min(size, partialBuffer.size() - sizeRead);
memcpy(buffer, &partialBuffer[sizeRead], toRead);
sizeRead += toRead;
return toRead;
} else {
size_t toRead = std::min(size, contentLength - sizeRead);
size_t read = recv(fd, buffer, toRead, 0);
sizeRead += read;
return read;
}
}
void close() {
}
size_t getTotalSize() { return contentLength; }
};
class FileResponseReader : public ResponseReader {
public:
FILE *file;
@@ -30,7 +71,7 @@ class FileResponseReader : public ResponseReader {
fileSize = ftell(file); // get current file pointer
fseek(file, 0, SEEK_SET); // seek back to beginning of file
};
~FileResponseReader() { fclose(file); };
size_t read(char *buffer, size_t size) {
return fread(buffer, 1, size, file);
@@ -48,10 +89,13 @@ enum class RequestType { GET, POST };
struct HTTPRequest {
std::map<std::string, std::string> urlParams;
std::map<std::string, std::string> queryParams;
std::unique_ptr<ResponseReader> responseReader = std::unique_ptr<RequestBodyReader>(nullptr);
std::string body;
std::string url;
int handlerId;
int connection;
int contentLength;
};
struct HTTPResponse {
@@ -64,19 +108,22 @@ struct HTTPResponse {
std::unique_ptr<ResponseReader> responseReader;
};
typedef std::function<void(HTTPRequest &)> httpHandler;
typedef std::function<void(std::unique_ptr<bell::HTTPRequest>)> httpHandler;
struct HTTPRoute {
RequestType requestType;
httpHandler handler;
bool readBodyToStr;
};
struct HTTPConnection {
int fd = 0;
std::vector<uint8_t> buffer;
std::string currentLine = "";
std::vector<uint8_t> partialBuffer = std::vector<uint8_t>();
int contentLength = 0;
bool isReadingBody = false;
std::string httpMethod;
bool toBeClosed = false;
bool headersRead = false;
bool isEventConnection = false;
bool isCaptivePortal = false;
};
@@ -96,10 +143,11 @@ public:
*
* @param requestType GET or POST
* @param endpoint registering under
* @param readResponseToStr if true, response will be read to string, otherwise it will return a reader object
* httpHandler lambda to be called when given endpoint gets executed
*/
virtual void registerHandler(RequestType requestType, const std::string & endpoint,
httpHandler) = 0;
httpHandler, bool readResponseToStr = true) = 0;
/**
* Writes given response to a fd

View File

@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <string>
#include <memory>
@@ -18,7 +19,7 @@ namespace bell
virtual void info(std::string filename, int line, std::string submodule, const char *format, ...) = 0;
};
extern std::shared_ptr<bell::AbstractLogger> bellGlobalLogger;
extern bell::AbstractLogger* bellGlobalLogger;
class BellLogger : public bell::AbstractLogger
{
public:
@@ -81,23 +82,27 @@ namespace bell
void printFilename(std::string filename)
{
#ifdef _WIN32
std::string basenameStr(filename.substr(filename.rfind("\\") + 1));
#else
std::string basenameStr(filename.substr(filename.rfind("/") + 1));
#endif
unsigned long hash = 5381;
for (char const &c : basenameStr)
{
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
printf("\e[0;%dm", allColors[hash % NColors]);
printf("\033[0;%dm", allColors[hash % NColors]);
printf("%s", basenameStr.c_str());
printf(colorReset);
}
private:
static constexpr const char *colorReset = "\e[0m";
static constexpr const char *colorRed = "\e[0;31m";
static constexpr const char *colorBlue = "\e[0;34m";
static constexpr const char *colorReset = "\033[0m";
static constexpr const char *colorRed = "\033[0;31m";
static constexpr const char *colorBlue = "\033[0;34m";
static constexpr const int NColors = 15;
static constexpr int allColors[NColors] = {31, 32, 33, 34, 35, 36, 37, 90, 91, 92, 93, 94, 95, 96, 97};
};

View File

@@ -7,9 +7,12 @@
#include <freertos/FreeRTOS.h>
#include <freertos/timers.h>
#include <freertos/task.h>
#elif _WIN32
#include <winsock2.h>
#else
#include <pthread.h>
#endif
#include <pthread.h>
#include <string>
namespace bell
@@ -62,14 +65,23 @@ namespace bell
esp_pthread_set_cfg(&cfg);
}
#endif
#if _WIN32
thread = CreateThread(NULL, stackSize, (LPTHREAD_START_ROUTINE) taskEntryFunc, this, 0, NULL);
return thread != NULL;
#else
return (pthread_create(&thread, NULL, taskEntryFunc, this) == 0);
#endif
}
protected:
virtual void runTask() = 0;
private:
#if _WIN32
HANDLE thread;
#else
pthread_t thread;
#endif
#ifdef ESP_PLATFORM
int priority;
StaticTask_t *xTaskBuffer;
@@ -96,7 +108,11 @@ namespace bell
{
Task* self = (Task*) This;
self->runTask();
#if _WIN32
WaitForSingleObject(self->thread, INFINITE);
#else
pthread_join(self->thread, NULL);
#endif
return NULL;
}
};

View File

@@ -18,6 +18,9 @@ void freeAndNull(void *&ptr);
#define BELL_SLEEP_MS(ms) vTaskDelay(ms / portTICK_PERIOD_MS)
#define BELL_YIELD() taskYIELD()
#elif defined(_WIN32)
#define BELL_SLEEP_MS(ms) Sleep(ms)
#define BELL_YIELD() ;
#else
#include <unistd.h>

View File

@@ -0,0 +1,127 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-7.
#pragma once
#include "ByteStream.h"
#include "BellTask.h"
#include "WrappedSemaphore.h"
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
/**
* This class implements a wrapper around an arbitrary bell::ByteStream,
* providing a circular reading buffer with configurable thresholds.
*
* The BufferedStream runs a bell::Task when it's started, so the caller can
* access the buffer's data asynchronously, whenever needed. The buffer is refilled
* automatically from source stream.
*
* The class implements bell::ByteStream's methods, although for proper functioning,
* the caller code should be modified to check isReady() and isNotReady() flags.
*
* If the actual reading code can't be modified, waitForReady allows to wait for buffer readiness
* during reading. Keep in mind that using the semaphore is probably more resource effective.
*
* The source stream (passed to open() or returned by the reader) should implement the read()
* method correctly, such as that 0 is returned if, and only if the stream ends.
*/
class BufferedStream : public bell::ByteStream, bell::Task {
public:
typedef std::shared_ptr<bell::ByteStream> StreamPtr;
typedef std::function<StreamPtr(uint32_t rangeStart)> StreamReader;
public:
/**
* @param taskName name to use for the reading task
* @param bufferSize total size of the reading buffer
* @param readThreshold how much can be read before refilling the buffer
* @param readSize amount of bytes to read from the source each time
* @param readyThreshold minimum amount of available bytes to report isReady()
* @param notReadyThreshold maximum amount of available bytes to report isNotReady()
* @param waitForReady whether to wait for the buffer to be ready during reading
* @param endWithSource whether to end the streaming as soon as source returns 0 from read()
*/
BufferedStream(
const std::string &taskName,
uint32_t bufferSize,
uint32_t readThreshold,
uint32_t readSize,
uint32_t readyThreshold,
uint32_t notReadyThreshold,
bool waitForReady = false);
~BufferedStream() override;
bool open(const StreamPtr &stream);
bool open(const StreamReader &newReader, uint32_t initialOffset = 0);
void close() override;
// inherited methods
public:
/**
* Read len bytes from the buffer to dst. If waitForReady is enabled
* and readAvailable is lower than notReadyThreshold, the function
* will block until readyThreshold bytes is available.
*
* @returns number of bytes copied to dst (might be lower than len,
* if the buffer does not contain len bytes available), or 0 if the source
* stream is already closed and there is no reader attached.
*/
size_t read(uint8_t *dst, size_t len) override;
size_t skip(size_t len) override;
size_t position() override;
size_t size() override;
// stream status
public:
/**
* Total amount of bytes served to read().
*/
uint32_t readTotal;
/**
* Total amount of bytes read from source.
*/
uint32_t bufferTotal;
/**
* Amount of bytes available to read from the buffer.
*/
std::atomic<uint32_t> readAvailable;
/**
* Whether the caller should start reading the data. This indicates that a safe
* amount (determined by readyThreshold) of data is available in the buffer.
*/
bool isReady() const;
/**
* Whether the caller should stop reading the data. This indicates that the amount of data
* available for reading is decreasing to a non-safe value, as data is being read
* faster than it can be buffered.
*/
bool isNotReady() const;
/**
* Semaphore that is given when the buffer becomes ready (isReady() == true). Caller can
* wait for the semaphore instead of continuously querying isReady().
*/
WrappedSemaphore readySem;
private:
std::mutex runningMutex;
bool running = false;
bool terminate = false;
WrappedSemaphore readSem; // signal to start writing to buffer after reading from it
std::mutex readMutex; // mutex for locking read operations during writing, and vice versa
uint32_t bufferSize;
uint32_t readAt;
uint32_t readSize;
uint32_t readyThreshold;
uint32_t notReadyThreshold;
bool waitForReady;
uint8_t *buf;
uint8_t *bufEnd;
uint8_t *bufReadPtr;
uint8_t *bufWritePtr;
StreamPtr source;
StreamReader reader;
void runTask() override;
void reset();
uint32_t lengthBetween(uint8_t *me, uint8_t *other);
};

View File

@@ -1,14 +1,78 @@
#ifndef BELL_CRYPTO_H
#define BELL_CRYPTO_H
#define Crypto CryptoMbedTLS
#include <vector>
#include <string>
#include <memory>
#include <mbedtls/base64.h>
#include <mbedtls/bignum.h>
#include <mbedtls/md.h>
#include <mbedtls/aes.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#define DH_KEY_SIZE 96
static unsigned char DHPrime[] = {
/* Well-known Group 1, 768-bit prime */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9,
0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6,
0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e,
0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e,
0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a,
0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14,
0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4,
0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static unsigned char DHGenerator[1] = {2};
class CryptoMbedTLS {
private:
mbedtls_md_context_t sha1Context;
mbedtls_aes_context aesCtx;
public:
CryptoMbedTLS();
~CryptoMbedTLS();
// Base64
std::vector<uint8_t> base64Decode(const std::string& data);
std::string base64Encode(const std::vector<uint8_t>& data);
// Sha1
void sha1Init();
void sha1Update(const std::string& s);
void sha1Update(const std::vector<uint8_t>& vec);
std::string sha1Final();
std::vector<uint8_t> sha1FinalBytes();
// HMAC SHA1
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, uint8_t* data, size_t nbytes);
// AES ECB
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
// Diffie Hellman
std::vector<uint8_t> publicKey;
std::vector<uint8_t> privateKey;
void dhInit();
std::vector<uint8_t> dhCalculateShared(const std::vector<uint8_t>& remoteKey);
// PBKDF2
std::vector<uint8_t> pbkdf2HmacSha1(const std::vector<uint8_t>& password, const std::vector<uint8_t>& salt, int iterations, int digestSize);
// Random stuff
std::vector<uint8_t> generateVectorWithRandomData(size_t length);
};
#ifdef BELL_USE_MBEDTLS
#include "CryptoMbedTLS.h"
#define Crypto CryptoMbedTLS
#else
#include "CryptoOpenSSL.h"
#define Crypto CryptoOpenSSL
#endif
#endif

View File

@@ -1,78 +0,0 @@
#ifndef BELL_CRYPTOMBEDTLS_H
#define BELL_CRYPTOMBEDTLS_H
#ifdef BELL_USE_MBEDTLS
#include <vector>
#include <string>
#include <memory>
#include <mbedtls/base64.h>
#include <mbedtls/bignum.h>
#include <mbedtls/md.h>
#include <mbedtls/aes.h>
#include <mbedtls/pkcs5.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#define DH_KEY_SIZE 96
static unsigned char DHPrime[] = {
/* Well-known Group 1, 768-bit prime */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9,
0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6,
0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e,
0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e,
0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a,
0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14,
0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4,
0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static unsigned char DHGenerator[1] = {2};
class CryptoMbedTLS {
private:
mbedtls_md_context_t sha1Context;
mbedtls_aes_context aesCtx;
public:
CryptoMbedTLS();
~CryptoMbedTLS();
// Base64
std::vector<uint8_t> base64Decode(const std::string& data);
std::string base64Encode(const std::vector<uint8_t>& data);
// Sha1
void sha1Init();
void sha1Update(const std::string& s);
void sha1Update(const std::vector<uint8_t>& vec);
std::string sha1Final();
std::vector<uint8_t> sha1FinalBytes();
// HMAC SHA1
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, uint8_t* data, size_t nbytes);
// AES ECB
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
// Diffie Hellman
std::vector<uint8_t> publicKey;
std::vector<uint8_t> privateKey;
void dhInit();
std::vector<uint8_t> dhCalculateShared(const std::vector<uint8_t>& remoteKey);
// PBKDF2
std::vector<uint8_t> pbkdf2HmacSha1(const std::vector<uint8_t>& password, const std::vector<uint8_t>& salt, int iterations, int digestSize);
// Random stuff
std::vector<uint8_t> generateVectorWithRandomData(size_t length);
};
#endif
#endif

View File

@@ -1,84 +0,0 @@
#ifndef BELL_CRYPTOOPENSSL_H
#define BELL_CRYPTOOPENSSL_H
#include <vector>
#include <string>
#include <memory>
#include <openssl/engine.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/dh.h>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/aes.h>
#include <openssl/modes.h>
#define DH_KEY_SIZE 96
static unsigned char DHPrime[] = {
/* Well-known Group 1, 768-bit prime */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9,
0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6,
0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e,
0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e,
0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a,
0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14,
0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4,
0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
static unsigned char DHGenerator[1] = {2};
class CryptoOpenSSL {
private:
DH* dhContext = nullptr;
SHA_CTX sha1Context;
public:
CryptoOpenSSL();
~CryptoOpenSSL();
// Base64
std::vector<uint8_t> base64Decode(const std::string& data);
std::string base64Encode(const std::vector<uint8_t>& data);
// Sha1
void sha1Init();
void sha1Update(const std::string& s);
void sha1Update(const std::vector<uint8_t>& vec);
void connectSSL(std::string url);
int readSSL(uint8_t* buf, int len);
int writeSSL(uint8_t* buf, int len);
void closeSSL();
std::string sha1Final();
std::vector<uint8_t> sha1FinalBytes();
// HMAC SHA1
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, uint8_t* buffer, size_t nbytes);
// AES ECB
void aesECBdecrypt(const std::vector<uint8_t>& key, std::vector<uint8_t>& data);
// Diffie Hellman
std::vector<uint8_t> publicKey;
std::vector<uint8_t> privateKey;
void dhInit();
std::vector<uint8_t> dhCalculateShared(const std::vector<uint8_t>& remoteKey);
// PBKDF2
std::vector<uint8_t> pbkdf2HmacSha1(const std::vector<uint8_t>& password, const std::vector<uint8_t>& salt, int iterations, int digestSize);
// Random stuff
std::vector<uint8_t> generateVectorWithRandomData(size_t length);
};
#endif

View File

@@ -4,7 +4,7 @@
#include "BellSocket.h"
#include "ByteStream.h"
#include "TCPSocket.h"
#include "platform/TLSSocket.h"
#include "TLSSocket.h"
#include <map>
#include <memory>
#include <string>

View File

@@ -11,16 +11,21 @@
#include <iostream>
#include <queue>
#include <stdio.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include "win32shim.h"
#else
#include <sys/select.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <sstream>
#include <BellLogger.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <sys/socket.h>
#include <string>
#include <netdb.h>
#include <mutex>
#include <fcntl.h>
#include "BaseHTTPServer.h"
@@ -46,7 +51,7 @@ namespace bell
std::map<int, HTTPConnection> connections;
void writeResponse(const HTTPResponse &);
void writeResponseEvents(int connFd);
void findAndHandleRoute(std::string &, std::string &, int connectionFd);
void findAndHandleRoute(HTTPConnection& connection);
std::vector<std::string> splitUrl(const std::string &url, char delimiter);
std::mutex responseMutex;
@@ -60,7 +65,7 @@ namespace bell
public:
HTTPServer(int serverPort);
void registerHandler(RequestType requestType, const std::string &, httpHandler);
void registerHandler(RequestType requestType, const std::string &, httpHandler, bool readDataToStr = false);
void respond(const HTTPResponse &);
void redirectTo(const std::string&, int connectionFd);
void publishEvent(std::string eventName, std::string eventData);

View File

@@ -6,7 +6,7 @@
#include <ByteStream.h>
#include <BellSocket.h>
#include <TCPSocket.h>
#include <platform/TLSSocket.h>
#include <TLSSocket.h>
/*
* HTTPStream

View File

@@ -9,15 +9,21 @@
#include <cstring>
#include <stdlib.h>
#include <sys/types.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include "win32shim.h"
#else
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#endif
#include <sstream>
#include <fstream>
#include <netinet/tcp.h>
#include <BellLogger.h>
#include <sys/ioctl.h>
namespace bell
{
@@ -77,18 +83,23 @@ namespace bell
}
size_t read(uint8_t *buf, size_t len) {
return recv(sockFd, buf, len, 0);
return recv(sockFd, (char*) buf, len, 0);
}
size_t write(uint8_t *buf, size_t len) {
return send(sockFd, buf, len, 0);
return send(sockFd, (char*) buf, len, 0);
}
size_t poll() {
int value;
ioctl(sockFd, FIONREAD, &value);
return value;
}
size_t poll() {
#ifdef _WIN32
unsigned long value;
ioctlsocket(sockFd, FIONREAD, &value);
#else
int value;
ioctl(sockFd, FIONREAD, &value);
#endif
return value;
}
void close() {
if (!isClosed) {

View File

@@ -8,50 +8,36 @@
#include <fstream>
#include <iostream>
#include <memory>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#include <sstream>
#include <stdlib.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#ifdef BELL_USE_MBEDTLS
#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
#else
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#endif
namespace bell {
class TLSSocket : public bell::Socket {
private:
#ifdef BELL_USE_MBEDTLS
mbedtls_net_context server_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
#else
BIO *sbio, *out;
int len;
char tmpbuf[1024];
SSL_CTX *ctx;
SSL *ssl;
int sockFd;
int sslFd;
#endif
bool isClosed = false;
public:

View File

@@ -0,0 +1,8 @@
//
// Created by Filip Grzywok on 28/02/2022.
//
#ifndef EUPHONIUMCLI_TIMEDEFS_H
#define EUPHONIUMCLI_TIMEDEFS_H
#endif // EUPHONIUMCLI_TIMEDEFS_H

View File

@@ -0,0 +1,19 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseCodec.h"
#include "aacdec.h"
class AACDecoder : public BaseCodec {
private:
HAACDecoder aac;
int16_t *pcmData;
AACFrameInfo frame = {};
public:
AACDecoder();
~AACDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,18 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseCodec.h"
#include "alac_wrapper.h"
class ALACDecoder : public BaseCodec {
private:
alac_codec_s* alacCodec;
int16_t *pcmData;
public:
ALACDecoder();
~ALACDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,23 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseCodec.h"
#include "BaseContainer.h"
#include <memory>
enum class AudioCodec {
UNKNOWN = 0,
AAC = 1,
MP3 = 2,
VORBIS = 3,
OPUS = 4,
FLAC = 5,
};
class AudioCodecs {
public:
static std::shared_ptr<BaseCodec> getCodec(AudioCodec type);
static std::shared_ptr<BaseCodec> getCodec(BaseContainer *container);
static void addCodec(AudioCodec type, const std::shared_ptr<BaseCodec> &codec);
};

View File

@@ -0,0 +1,39 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
#include "BaseContainer.h"
class BaseCodec {
public:
/**
* Setup the codec (sample rate, channel count, etc) using the specified container.
*/
virtual bool setup(BaseContainer *container);
/**
* Setup the codec manually, using the provided values.
*/
virtual bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) = 0;
/**
* Decode the given sample.
*
* @param [in] inData encoded data. Should allow nullptr, in which case nullptr should be returned.
* @param [in] inLen size of inData, in bytes
* @param [out] outLen size of output PCM data, in bytes
* @return pointer to decoded raw PCM audio data, allocated inside the codec object; nullptr on failure
*/
virtual uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) = 0;
/**
* Read a single sample from the container, decode it, and return the result.
*
* @param [in] container media container to read the sample from (the container's codec must match this instance)
* @param [out] outLen size of output PCM data, in bytes
* @return pointer to decoded raw PCM audio data, allocated inside the codec object; nullptr on failure
*/
uint8_t *decode(BaseContainer *container, uint32_t &outLen);
/**
* Last error that occurred, this is a codec-specific value.
* This may be set by a codec upon decoding failure.
*/
int lastErrno = -1;
};

View File

@@ -43,7 +43,7 @@ namespace bell
}
};
extern std::shared_ptr<bell::DecodersInstance> decodersInstance;
extern bell::DecodersInstance* decodersInstance;
void createDecoders();
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
#pragma once
#include "BaseCodec.h"
#include "mp3dec.h"
class MP3Decoder : public BaseCodec {
private:
HMP3Decoder mp3;
int16_t *pcmData;
MP3FrameInfo frame = {};
public:
MP3Decoder();
~MP3Decoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,19 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
#pragma once
#include "BaseCodec.h"
struct OpusDecoder;
class OPUSDecoder : public BaseCodec {
private:
OpusDecoder *opus;
int16_t *pcmData;
public:
OPUSDecoder();
~OPUSDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
};

View File

@@ -0,0 +1,25 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
#pragma once
#include "BaseCodec.h"
#include "ivorbiscodec.h"
class VorbisDecoder : public BaseCodec {
private:
vorbis_info *vi = nullptr;
vorbis_comment *vc = nullptr;
vorbis_dsp_state *vd = nullptr;
ogg_packet op = {};
int16_t *pcmData;
public:
VorbisDecoder();
~VorbisDecoder();
bool setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) override;
uint8_t *decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) override;
bool setup(BaseContainer *container) override;
private:
void setPacket(uint8_t *inData, uint32_t inLen) const;
};

View File

@@ -0,0 +1,10 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-15.
#pragma once
#include "BaseContainer.h"
class AudioContainers {
public:
static std::unique_ptr<BaseContainer> create(const char *mimeType);
};

View File

@@ -0,0 +1,104 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-7.
#pragma once
#include "BinaryReader.h"
#include "ByteStream.h"
#include <cstdint>
#include <memory>
/**
* Either the media file or the requested position/offset is not loaded yet.
*/
#define SAMPLE_NOT_LOADED -1
/**
* The media file does not contain the requested position/offset.
*/
#define SAMPLE_NOT_FOUND -2
/**
* The file is not seekable (i.e. doesn't contain an index table).
*/
#define SAMPLE_NOT_SEEKABLE -3
enum class AudioCodec;
class BaseContainer {
public:
BaseContainer() = default;
/**
* Feed a new data source to the container.
* @param stream ByteStream reading source data
* @param position absolute position of the current ByteStream within the source media
*/
virtual void feed(const std::shared_ptr<bell::ByteStream> &stream, uint32_t position);
/**
* Try to parse the media provided by the source stream.
* @return whether parsing was successful
*/
virtual bool parse() = 0;
/**
* Get absolute offset within the source media for the given timestamp.
* When seeking to a specified time, the caller should run feed() with a stream
* reader starting at the returned offset. Depending on the container type,
* the returned offset may not point to the exact time position (i.e. chunks with
* headers), so seekTo() should be used afterwards.
*
* @param timeMs requested timestamp, in milliseconds
* @return byte offset within the source media that should be loaded
* in order to seek to the requested position; negative value on error
*/
virtual int32_t getLoadingOffset(uint32_t timeMs) = 0;
/**
* Try to seek to the specified position (in milliseconds), using the currently
* loaded source stream. This method will fail if the source stream does not yield
* data for the requested position, or block until the stream loads data for this position.
*
* @param timeMs requested timestamp, in milliseconds
*/
virtual bool seekTo(uint32_t timeMs) = 0;
/**
* Get the current playback position, in milliseconds. May return -1 if the track
* is not playing (has ended or not started yet).
*/
virtual int32_t getCurrentTimeMs() = 0;
/**
* Read an encoded audio sample from the container, starting at the current position.
*
* @param [out] len length of the data stored in the returned pointer, in bytes
* @return pointer to data allocated inside the container object; should not be freed or changed.
* On failure, nullptr is returned, and len is left unchanged.
*/
virtual uint8_t *readSample(uint32_t &len) = 0;
/**
* Get optional initialization data for the specified codec. This may be used by a codec,
* for containers that contain the setup data.
*
* @param [out] len length of the setup data
* @return ptr to [len] setup data bytes, or nullptr if not available/not supported
*/
virtual uint8_t *getSetupData(uint32_t &len, AudioCodec matchCodec) = 0;
public:
bool closed = false;
bool isSeekable = false;
// audio parameters
AudioCodec codec = (AudioCodec)0;
uint32_t sampleRate = 0;
uint8_t channelCount = 0;
uint8_t bitDepth = 0;
uint32_t durationMs = 0;
protected:
std::unique_ptr<bell::BinaryReader> reader;
std::shared_ptr<bell::ByteStream> source;
uint32_t pos = 0;
uint8_t readUint8();
uint16_t readUint16();
uint32_t readUint24();
uint32_t readUint32();
uint64_t readUint64();
uint32_t readVarint32();
uint32_t readBytes(uint8_t *dst, uint32_t num);
uint32_t skipBytes(uint32_t num);
uint32_t skipTo(uint32_t offset);
};

View File

@@ -0,0 +1,108 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-8.
#pragma once
#include <cstdint>
enum class AudioSampleFormat;
enum class MP4AObjectType;
enum class MP4AProfile;
typedef struct {
/** Absolute offset of mdat header (or moof for fMP4) */
uint32_t start;
/** Absolute offset of the last mdat byte */
uint32_t end;
/** Total duration of this fragment */
uint32_t duration;
} Mpeg4Fragment;
typedef struct {
/** Number of chunks this descriptor applies to */
uint16_t count;
/** Number of samples in the described chunks */
uint32_t samples;
uint16_t sampleDescriptionId;
} Mpeg4ChunkRange;
/** Absolute offset of the chunk data */
typedef uint32_t Mpeg4ChunkOffset;
typedef struct {
/** Abs. offset of data start in the current chunk */
uint32_t start;
/** Abs. offset of data end in the current chunk */
uint32_t end;
/** Abs. offset of the next chunk data, or 0 for last chunk in a fragment */
uint32_t nextStart;
} Mpeg4Chunk;
typedef struct {
/** Number of samples this descriptor applies to */
uint32_t count;
/** Duration of the described samples */
uint32_t duration;
} Mpeg4SampleRange;
/** Size of a single sample */
typedef uint32_t Mpeg4SampleSize;
/** Flags for a sample */
typedef uint32_t SampleFlags;
/** Default values for samples in the movie/fragment */
typedef struct {
/** Absolute offset of first mdat byte */
uint32_t offset;
uint32_t sampleDescriptionId;
uint32_t duration;
uint32_t size;
SampleFlags flags;
} SampleDefaults;
/** Sample Description Table */
typedef struct {
uint16_t dataReferenceIndex;
AudioSampleFormat format;
// params for MPEG-4 Elementary Stream Descriptors
MP4AObjectType mp4aObjectType;
MP4AProfile mp4aProfile;
// atom header for unknown descriptors
uint32_t dataType;
// codec-specific data (either DecoderSpecificInfo or the entire descriptor)
uint32_t dataLength;
uint8_t *data;
} SampleDescription;
typedef struct {
// byte 1 - bits 0:7
bool durationIsEmpty : 1;
bool defaultBaseIsMoof : 1;
bool dummy1 : 6;
// byte 2 - bits 0:7
uint8_t dummy2 : 8;
// byte 3 - bits 0:7
bool baseDataOffsetPresent : 1;
bool sampleDescriptionIndexPresent : 1;
bool dummy3 : 1;
bool defaultSampleDurationPresent : 1;
bool defaultSampleSizePresent : 1;
bool defaultSampleFlagsPresent : 1;
bool dummy4 : 2;
} TfFlags;
typedef struct {
// byte 1 - bits 0:7
uint8_t dummy1 : 8;
// byte 2 - bits 0:7
bool sampleDurationPresent : 1;
bool sampleSizePresent : 1;
bool sampleFlagsPresent : 1;
bool sampleCompositionTimeOffsetsPresent : 1;
bool dummy2 : 4;
// byte 3 - bits 0:7
bool dataOffsetPresent : 1;
bool dummy3 : 1;
bool firstSampleFlagsPresent : 1;
bool dummy4 : 5;
} TrFlags;

View File

@@ -0,0 +1,114 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-8.
#pragma once
#include "BaseContainer.h"
#include "Mpeg4Atoms.h"
#include <memory>
class Mpeg4Container : public BaseContainer {
public:
~Mpeg4Container();
/**
* Start parsing the MP4 file. This method expects the source to read from 0th byte.
* This method leaves pos at first mdat data byte, or mdat header for fMP4 files.
*/
bool parse() override;
int32_t getLoadingOffset(uint32_t timeMs) override;
bool seekTo(uint32_t timeMs) override;
int32_t getCurrentTimeMs() override;
uint8_t *readSample(uint32_t &len) override;
uint8_t *getSetupData(uint32_t &len, AudioCodec matchCodec) override;
void feed(const std::shared_ptr<bell::ByteStream> &stream, uint32_t position) override;
private:
/**
* Parse a single movie fragment. This method expects the source to read moof data, without the header.
* After running, [pos] is left at next mdat header. A new fragment will be created if [pos] does not exist
* in [fragments] table.
*/
bool parseMoof(uint32_t moofSize);
bool goToData();
// char mediaBrand[5];
uint32_t totalDuration;
bool totalDurationPresent = false;
int8_t audioTrackId = -1;
uint32_t timescale = 0;
uint32_t sampleSizeMax = 0;
uint8_t *sampleData = nullptr;
uint32_t sampleDataLen = 0;
bool isParsed = false;
bool isFragmented = false;
/** True if source reads **audio** mdat data bytes, false if source reads atom headers */
bool isInData = false;
private: // data for the entire movie:
/** All fragments in the MPEG file */
Mpeg4Fragment *fragments;
uint16_t fragmentsLen;
/** Default sample descriptions for each track */
SampleDefaults *sampleDefs;
uint32_t sampleDefsLen;
/** Track IDs of [sampleDef] items */
uint32_t *sampleDefTracks;
/** Sample Description Table */
SampleDescription *sampleDesc;
uint32_t sampleDescLen;
private: // data changing every fragment:
/** Chunks in the current fragment */
Mpeg4ChunkRange *chunks;
uint32_t chunksLen;
/** Absolute chunk offsets in the current fragment */
Mpeg4ChunkOffset *chunkOffsets;
uint32_t chunkOffsetsLen;
/** All sample descriptors in the current fragment */
Mpeg4SampleRange *samples;
uint32_t samplesLen;
/** All sample sizes in the current fragment */
Mpeg4SampleSize *sampleSizes;
uint32_t sampleSizesLen;
private: // current status and position within the file
/** Currently loaded fragment (ptr) */
Mpeg4Fragment *curFragment;
/** The chunk currently being processed */
Mpeg4Chunk curChunk;
/** Size of the current sample (ptr) */
Mpeg4SampleSize *curSampleSize;
private: // Mpeg4Utils.cpp
void readAtomHeader(uint32_t &size, uint32_t &type);
void freeAll();
void freeFragment();
SampleDefaults *getSampleDef(uint32_t trackId);
void setCurrentFragment();
void setCurrentSample();
static bool isInFragment(Mpeg4Fragment *f, uint32_t offset);
static AudioCodec getCodec(SampleDescription *desc);
Mpeg4Fragment *createFragment();
int64_t findSample(int64_t byTime, int32_t byPos, uint64_t startTime);
private: // Mpeg4Parser.cpp
/** Populate [chunks] using the Sample-to-chunk Table */
void readStsc();
/** Populate [chunkOffsets] using the Chunk Offset Table */
void readStco();
/** Populate [samples] using the Time-to-sample Table */
void readStts();
/** Populate [sampleSizes] using the Sample Size Table */
void readStsz();
/** Populate [sampleDesc] using the Sample Description Table */
void readStsd();
private: // Mpeg4ParserFrag.cpp
/** Populate [fragments] using the Segment Index Table */
void readSidx(uint32_t atomSize);
/** Populate [sampleDefs] using Track Extends */
void readTrex();
/** Populate [sampleDefs] using Track Fragment Header */
void readTfhd(uint32_t trafEnd, uint32_t moofOffset);
/** Populate [chunks, chunkOffsets, samples, sampleSizes] using Track Fragment Run Table */
void readTrun(uint32_t atomSize, uint32_t moofOffset);
void allocSampleData();
};

View File

@@ -0,0 +1,206 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
#pragma once
enum class AtomType {
/** File Type */
ATOM_FTYP = 0x66747970,
/** Movie */
ATOM_MOOV = 0x6D6F6F76,
/** Movie Header */
ATOM_MVHD = 0x6D766864,
/** Movie Extends */
ATOM_MVEX = 0x6D766578,
/** Movie Extends Header */
ATOM_MEHD = 0x6D656864,
/** Track Extends */
ATOM_TREX = 0x74726578,
/** Track */
ATOM_TRAK = 0x7472616B,
/** Track Header */
ATOM_TKHD = 0x746B6864,
/** Edit */
ATOM_EDTS = 0x65647473,
/** Edit List */
ATOM_ELST = 0x656C7374,
/** Media */
ATOM_MDIA = 0x6D646961,
/** Media Header */
ATOM_MDHD = 0x6D646864,
/** Handler Reference */
ATOM_HDLR = 0x68646C72,
/** Handler Type - Sound */
ATOM_SOUN = 0x736F756E,
/** Handler Type - Video */
ATOM_VIDE = 0x76696465,
/** Handler Type - Subtitle */
ATOM_SUBT = 0x73756274,
/** Media Information */
ATOM_MINF = 0x6D696E66,
/** Data Information */
ATOM_DINF = 0x64696E66,
/** Data Reference */
ATOM_DREF = 0x64726566,
/** Data Entry Url */
ATOM_URL = 0x75726C20,
/** Sample Table */
ATOM_STBL = 0x7374626C,
/** Sample Description */
ATOM_STSD = 0x73747364,
/** siDecompressionParam */
ATOM_WAVE = 0x77617665,
/** Format Atom */
ATOM_FRMA = 0x66726D61,
/** Audio Channel Layout Atom */
ATOM_CHAN = 0x6368616E,
/** Terminator Atom */
ATOM_TERM = 0x00000000,
/** MPEG-4 Elementary Stream Descriptor */
ATOM_ESDS = 0x65736473,
/** Time-to-sample Table */
ATOM_STTS = 0x73747473,
/** Sync Sample Table */
ATOM_STSS = 0x73747373,
/** Sample-to-chunk Table */
ATOM_STSC = 0x73747363,
/** Chunk Offset Table */
ATOM_STCO = 0x7374636F,
/** Sample Size Table */
ATOM_STSZ = 0x7374737A,
/** Sound Media Header */
ATOM_SMHD = 0x736D6864,
/** Segment Index Table */
ATOM_SIDX = 0x73696478,
/** Movie Fragment */
ATOM_MOOF = 0x6D6F6F66,
/** Movie Fragment Header */
ATOM_MFHD = 0x6D666864,
/** Track Fragment */
ATOM_TRAF = 0x74726166,
/** Track Fragment Header */
ATOM_TFHD = 0x74666864,
/** Track Fragment Run */
ATOM_TRUN = 0x7472756E,
/** Media Data */
ATOM_MDAT = 0x6D646174,
};
// These formats are the direct sub-children of the stsd atom.
// https://mp4ra.org/#/codecs (+additions)
enum class AudioSampleFormat {
UNDEFINED = 0,
A3DS = 0x61336473, // Auro-Cx 3D audio
AC3 = 0x61632d33, // AC-3 audio
AC4 = 0x61632d34, // AC-4 audio
AGSM = 0x6167736d, // GSM
ALAC = 0x616c6163, // Apple lossless audio codec
ALAW = 0x616c6177, // a-Law
CAVS = 0x63617673, // AVS2-P3 codec
DRA1 = 0x64726131, // DRA Audio
DTS_MINUS = 0x6474732d, // Dependent base layer for DTS layered audio
DTS_PLUS = 0x6474732b, // Enhancement layer for DTS layered audio
DTSC = 0x64747363, // Core Substream
DTSE = 0x64747365, // Extension Substream containing only LBR
DTSH = 0x64747368, // Core Substream + Extension Substream
DTSL = 0x6474736c, // Extension Substream containing only XLL
DTSX = 0x64747378, // DTS-UHD profile 2
DTSY = 0x64747379, // DTS-UHD profile 3 or higher
DVI = 0x64766920, // DVI (as used in RTP, 4:1 compression)
EC3 = 0x65632d33, // Enhanced AC-3 audio
ENCA = 0x656e6361, // Encrypted/Protected audio
FL32 = 0x666c3332, // 32 bit float
FL64 = 0x666c3634, // 64 bit float
FLAC = 0x664c6143, // Free Lossless Audio Codec
G719 = 0x67373139, // ITU-T Recommendation G.719 (2008)
G726 = 0x67373236, // ITU-T Recommendation G.726 (1990)
IMA4 = 0x696d6134, // IMA (International Multimedia Assocation, defunct, 4:1)
IN24 = 0x696e3234, // 24 bit integer uncompressed
IN32 = 0x696e3332, // 32 bit integer uncompressed
LPCM = 0x6c70636d, // Uncompressed audio (various integer and float formats)
M4AE = 0x6d346165, // MPEG-4 Audio Enhancement
MHA1 = 0x6d686131, // MPEG-H Audio (single stream, unencapsulated)
MHA2 = 0x6d686132, // MPEG-H Audio (multi-stream, unencapsulated)
MHM1 = 0x6d686d31, // MPEG-H Audio (single stream, MHAS encapsulated)
MHM2 = 0x6d686d32, // MPEG-H Audio (multi-stream, MHAS encapsulated)
MLPA = 0x6d6c7061, // MLP Audio
MP4A = 0x6d703461, // MPEG-4 Audio
OPUS = 0x4f707573, // Opus audio coding
QCLP = 0x51636c70, // Qualcomm PureVoice
QDM2 = 0x51444d32, // Qdesign music 2
QDMC = 0x51444d43, // Qdesign music 1
RAW = 0x72617720, // Uncompressed audio
SAMR = 0x73616d72, // Narrowband AMR voice
SAWB = 0x73617762, // Wideband AMR voice
SAWP = 0x73617770, // Extended AMR-WB (AMR-WB+)
SEVC = 0x73657663, // EVRC Voice
SEVS = 0x73657673, // Enhanced Voice Services (EVS)
SQCP = 0x73716370, // 13K Voice
SSMV = 0x73736d76, // SMV Voice
TWOS = 0x74776f73, // Uncompressed 16-bit audio
ULAW = 0x756c6177, // Samples have been compressed using uLaw 2:1.
VDVA = 0x76647661, // DV audio (variable duration per video frame)
};
// These are present in the DecoderConfigDescriptor tag in ESDS (for AudioSampleFormat::FORMAT_MP4A).
// Source: https://mp4ra.org/#/codecs
enum class MP4AObjectType {
UNDEFINED = 0,
_13K = 0xE1, // 13K Voice
AAC_LC = 0x67, // ISO/IEC 13818-7 (AAC) Low Complexity Profile
AAC_MAIN = 0x66, // ISO/IEC 13818-7 (AAC) Main Profile
AAC_SSR = 0x68, // ISO/IEC 13818-7 (AAC) Scaleable Sampling Rate Profile
AC3 = 0xA5, // AC-3
AC3_ENH = 0xA6, // Enhanced AC-3
AC4 = 0xAE, // AC-4
AURO_CX_3D = 0xAF, // Auro-Cx 3D audio
DRA = 0xA7, // DRA Audio
DTS_CORE = 0xA9, // Core Substream
DTS_CORE_EXT = 0xAA, // Core Substream + Extension Substream
DTS_LBR = 0xAC, // Extension Substream containing only LBR
DTS_UHD2 = 0xB2, // DTS-UHD profile 2
DTS_UHD3 = 0xB3, // DTS-UHD profile 3 or higher
DTS_XLL = 0xAB, // Extension Substream containing only XLL
EVRC = 0xA0, // EVRC Voice
G719 = 0xA8, // ITU G.719 Audio
MP4A = 0x40, // ISO/IEC 14496-3 (MPEG-4 Audio)
MPEG1 = 0x6B, // ISO/IEC 11172-3 (MPEG-1 Part 3)
MPEG2 = 0x69, // ISO/IEC 13818-3 (MPEG-2 Part 3)
OPUS = 0xAD, // Opus audio
SMV = 0xA1, // SMV Voice
VORBIS = 0xDD, // Vorbis
};
// These are present in the DecoderSpecificInfo tag in ESDS (for MP4AObjectType::TYPE_MP4A).
// Source: https://wiki.multimedia.cx/index.php/MPEG-4_Audio
enum class MP4AProfile {
UNDEFINED = 0,
AAC_MAIN = 1, // AAC main
AAC_LC = 2, // AAC LC
AAC_SSR = 3, // AAC SSR
AAC_LTP = 4, // AAC LTP
SBR = 5, // SBR
AAC_SCALABLE = 6, // AAC Scalable
TWINVQ = 7, // TwinVQ
CELP = 8, // CELP
HVXC = 9, // HVXC
TTSI = 12, // TTSI
MAIN_SYNTHETIC = 13, // Main synthetic
WAVETABLE_SYNTHESIS = 14, // Wavetable synthesis
GENERAL_MIDI = 15, // General MIDI
ALGORITHMIC_SYNTHESIS_AND_AUDIO_FX = 16, // Algorithmic Synthesis and Audio FX
ER_AAC_LC = 17, // ER AAC LC
ER_AAC_LTP = 19, // ER AAC LTP
ER_AAC_SCALABLE = 20, // ER AAC Scalable
ER_TWINVQ = 21, // ER TwinVQ
ER_BSAC = 22, // ER BSAC
ER_AAC_LD = 23, // ER AAC LD
ER_CELP = 24, // ER CELP
ER_HVXC = 25, // ER HVXC
ER_HILN = 26, // ER HILN
ER_PARAMETRIC = 27, // ER Parametric
SSC = 28, // SSC
LAYER_1 = 32, // Layer-1
LAYER_2 = 33, // Layer-2
LAYER_3 = 34, // Layer-3
DST = 35, // DST
};

View File

@@ -0,0 +1,81 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-16.
#pragma once
#include "BaseContainer.h"
enum class ElementId;
class WebmContainer : public BaseContainer {
public:
~WebmContainer();
bool parse() override;
int32_t getLoadingOffset(uint32_t timeMs) override;
bool seekTo(uint32_t timeMs) override;
int32_t getCurrentTimeMs() override;
uint8_t *readSample(uint32_t &len) override;
uint8_t *getSetupData(uint32_t &len, AudioCodec matchCodec) override;
void feed(const std::shared_ptr<bell::ByteStream> &stream, uint32_t position) override;
private:
typedef struct {
uint32_t time;
uint32_t offset;
} CuePoint;
private:
// used while parsing
uint32_t esize;
ElementId eid;
// container parameters
char *docType = nullptr;
uint8_t audioTrackId = 255;
float timescale = 0.0f;
char *codecId = nullptr;
uint8_t *codecPrivate = nullptr;
uint32_t codecPrivateLen = 0;
// container state
CuePoint *cues = nullptr;
uint16_t cuesLen = 0;
uint32_t clusterEnd = 0;
uint32_t clusterTime = 0;
uint32_t currentTime = 0;
bool isParsed = false;
// buffer
uint8_t *sampleData = nullptr;
uint32_t sampleLen = 0;
// lacing parameters
uint32_t *laceSizes = nullptr;
uint32_t *laceCurrent = nullptr;
uint8_t laceLeft = 0;
// set to read the current buffer instead of loading new frames
uint16_t readOutFrameSize = 0;
private:
uint32_t readVarNum32(bool raw = false);
uint64_t readVarNum64();
uint32_t readUint(uint8_t len);
uint64_t readUlong(uint8_t len);
float readFloat(uint8_t len);
void readElem();
void parseSegment(uint32_t start);
void parseTrack(uint32_t end);
void parseCuePoint(uint16_t idx, uint32_t end, uint32_t segmentStart);
/**
* Continue reading elements until a block is encountered.
*
* If [untilTime] is set, the method will keep reading until [currentTime]
* is less than [untilTime]. Because of how WebM works, [pos] will be one frame later
* than the requested time, although the container will report the correct position.
*
* @return size of the frame pointed by [pos]
*/
uint32_t readCluster(uint32_t untilTime = 0);
/**
* Parse a single block within a cluster. This method will populate lacing parameters if needed.
* @param end offset of the next byte after this block
* @return size of the frame pointed by [pos]
*/
uint32_t readBlock(uint32_t end);
uint8_t *readFrame(uint32_t size, uint32_t &outLen);
};

View File

@@ -0,0 +1,713 @@
// Copyright (c) Kuba Szczodrzyński 2022-1-16.
#pragma once
enum class ElementId {
/** [sub-elements] Set the EBML characteristics of the data to follow. Each EBML document has to start with this. */
EBML = 0x1A45DFA3,
/** [u-integer] The version of EBML parser used to create the file. */
EBMLVersion = 0x4286,
/** [u-integer] The minimum EBML version a parser has to support to read this file. */
EBMLReadVersion = 0x42F7,
/** [u-integer] The maximum length of the IDs you'll find in this file (4 or less in Matroska). */
EBMLMaxIDLength = 0x42F2,
/** [u-integer] The maximum length of the sizes you'll find in this file (8 or less in Matroska). This does not
override the element size indicated at the beginning of an element. Elements that have an indicated size which is
larger than what is allowed by EBMLMaxSizeLength shall be considered invalid. */
EBMLMaxSizeLength = 0x42F3,
/** [string] A string that describes the type of document that follows this EBML header ('matroska' in our case). */
DocType = 0x4282,
/** [u-integer] The version of DocType interpreter used to create the file. */
DocTypeVersion = 0x4287,
/** [u-integer] The minimum DocType version an interpreter has to support to read this file. */
DocTypeReadVersion = 0x4285,
/** [binary] The CRC is computed on all the data from the last CRC element (or start of the upper level element), up
to the CRC element, including other previous CRC elements. All level 1 elements should include a CRC-32. */
CRC32 = 0xBF,
/** [binary] Used to void damaged data, to avoid unexpected behaviors when using damaged data. The content is
discarded. Also used to reserve space in a sub-element for later use. */
Void = 0xEC,
/** [sub-elements] Contain signature of some (coming) elements in the stream. */
SignatureSlot = 0x1B538667,
/** [u-integer] Signature algorithm used (1=RSA, 2=elliptic). */
SignatureAlgo = 0x7E8A,
/** [u-integer] Hash algorithm used (1=SHA1-160, 2=MD5). */
SignatureHash = 0x7E9A,
/** [binary] The public key to use with the algorithm (in the case of a PKI-based signature). */
SignaturePublicKey = 0x7EA5,
/** [binary] The signature of the data (until a new. */
Signature = 0x7EB5,
/** [sub-elements] Contains elements that will be used to compute the signature. */
SignatureElements = 0x7E5B,
/** [sub-elements] A list consists of a number of consecutive elements that represent one case where data is used in
signature. Ex: Cluster|Block|BlockAdditional means that the BlockAdditional of all Blocks in all Clusters is used
for encryption. */
SignatureElementList = 0x7E7B,
/** [binary] An element ID whose data will be used to compute the signature. */
SignedElement = 0x6532,
/* ebml_matroska.xml */
/** [master] The Root Element that contains all other Top-Level Elements (Elements defined only at Level 1). A
Matroska file is composed of 1 Segment. */
Segment = 0x18538067,
/** [master] Contains the Segment Position of other Top-Level Elements. */
SeekHead = 0x114D9B74,
/** [master] Contains a single seek entry to an EBML Element. */
Seek = 0x4DBB,
/** [binary] The binary ID corresponding to the Element name. */
SeekID = 0x53AB,
/** [uinteger] The Segment Position of the Element. */
SeekPosition = 0x53AC,
/** [master] Contains general information about the Segment. */
Info = 0x1549A966,
/** [binary] A randomly generated unique ID to identify the Segment amongst many others (128 bits). */
SegmentUID = 0x73A4,
/** [utf-8] A filename corresponding to this Segment. */
SegmentFilename = 0x7384,
/** [binary] A unique ID to identify the previous Segment of a Linked Segment (128 bits). */
PrevUID = 0x3CB923,
/** [utf-8] A filename corresponding to the file of the previous Linked Segment. */
PrevFilename = 0x3C83AB,
/** [binary] A unique ID to identify the next Segment of a Linked Segment (128 bits). */
NextUID = 0x3EB923,
/** [utf-8] A filename corresponding to the file of the next Linked Segment. */
NextFilename = 0x3E83BB,
/** [binary] A randomly generated unique ID that all Segments of a Linked Segment **MUST** share (128 bits). */
SegmentFamily = 0x4444,
/** [master] The mapping between this `Segment` and a segment value in the given Chapter Codec. */
ChapterTranslate = 0x6924,
/** [binary] The binary value used to represent this Segment in the chapter codec data. The format depends on the
ChapProcessCodecID used; see (#chapprocesscodecid-element). */
ChapterTranslateID = 0x69A5,
/** [uinteger] This `ChapterTranslate` applies to this chapter codec of the given chapter edition(s); see
(#chapprocesscodecid-element). */
ChapterTranslateCodec = 0x69BF,
/** [uinteger] Specify a chapter edition UID on which this `ChapterTranslate` applies. */
ChapterTranslateEditionUID = 0x69FC,
/** [uinteger] Timestamp scale in nanoseconds (1.000.000 means all timestamps in the Segment are expressed in
milliseconds). */
TimestampScale = 0x2AD7B1,
/** [float] Duration of the Segment in nanoseconds based on TimestampScale. */
Duration = 0x4489,
/** [date] The date and time that the Segment was created by the muxing application or library. */
DateUTC = 0x4461,
/** [utf-8] General name of the Segment. */
Title = 0x7BA9,
/** [utf-8] Muxing application or library (example: "libmatroska-0.4.3"). */
MuxingApp = 0x4D80,
/** [utf-8] Writing application (example: "mkvmerge-0.3.3"). */
WritingApp = 0x5741,
/** [master] The Top-Level Element containing the (monolithic) Block structure. */
Cluster = 0x1F43B675,
/** [uinteger] Absolute timestamp of the cluster (based on TimestampScale). */
Timestamp = 0xE7,
/** [master] The list of tracks that are not used in that part of the stream. It is useful when using overlay tracks
on seeking or to decide what track to use. */
SilentTracks = 0x5854,
/** [uinteger] One of the track number that are not used from now on in the stream. It could change later if not
specified as silent in a further Cluster. */
SilentTrackNumber = 0x58D7,
/** [uinteger] The Segment Position of the Cluster in the Segment (0 in live streams). It might help to
resynchronise offset on damaged streams. */
Position = 0xA7,
/** [uinteger] Size of the previous Cluster, in octets. Can be useful for backward playing. */
PrevSize = 0xAB,
/** [binary] Similar to Block, see (#block-structure), but without all the extra information, mostly used to reduced
overhead when no extra feature is needed; see (#simpleblock-structure) on SimpleBlock Structure. */
SimpleBlock = 0xA3,
/** [master] Basic container of information containing a single Block and information specific to that Block. */
BlockGroup = 0xA0,
/** [binary] Block containing the actual data to be rendered and a timestamp relative to the Cluster Timestamp; see
(#block-structure) on Block Structure. */
Block = 0xA1,
/** [binary] A Block with no data. It **MUST** be stored in the stream at the place the real Block would be in
display order. */
BlockVirtual = 0xA2,
/** [master] Contain additional blocks to complete the main one. An EBML parser that has no knowledge of the Block
structure could still see and use/skip these data. */
BlockAdditions = 0x75A1,
/** [master] Contain the BlockAdditional and some parameters. */
BlockMore = 0xA6,
/** [uinteger] An ID to identify the BlockAdditional level. If BlockAddIDType of the corresponding block is 0, this
value is also the value of BlockAddIDType for the meaning of the content of BlockAdditional. */
BlockAddID = 0xEE,
/** [binary] Interpreted by the codec as it wishes (using the BlockAddID). */
BlockAdditional = 0xA5,
/** [uinteger] The duration of the Block (based on TimestampScale). The BlockDuration Element can be useful at the
end of a Track to define the duration of the last frame (as there is no subsequent Block available), or when
there is a break in a track like for subtitle tracks. */
BlockDuration = 0x9B,
/** [uinteger] This frame is referenced and has the specified cache priority. In cache only a frame of the same or
higher priority can replace this frame. A value of 0 means the frame is not referenced. */
ReferencePriority = 0xFA,
/** [integer] A timestamp value, relative to the timestamp of the Block in this BlockGroup. This is used to
reference other frames necessary to decode this frame. The relative value **SHOULD** correspond to a valid
`Block` this `Block` depends on. Historically Matroska Writer didn't write the actual `Block(s)` this `Block`
depends on, but *some* `Block` in the past. The value "0" **MAY** also be used to signify this `Block` cannot be
decoded on its own, but without knownledge of which `Block` is necessary. In this case, other `ReferenceBlock`
**MUST NOT** be found in the same `BlockGroup`. If the `BlockGroup` doesn't have any `ReferenceBlock` element,
then the `Block` it contains can be decoded without using any other `Block` data. */
ReferenceBlock = 0xFB,
/** [integer] The Segment Position of the data that would otherwise be in position of the virtual block. */
ReferenceVirtual = 0xFD,
/** [binary] The new codec state to use. Data interpretation is private to the codec. This information **SHOULD**
always be referenced by a seek entry. */
CodecState = 0xA4,
/** [integer] Duration in nanoseconds of the silent data added to the Block (padding at the end of the Block for
positive value, at the beginning of the Block for negative value). The duration of DiscardPadding is not
calculated in the duration of the TrackEntry and **SHOULD** be discarded during playback. */
DiscardPadding = 0x75A2,
/** [master] Contains slices description. */
Slices = 0x8E,
/** [master] Contains extra time information about the data contained in the Block. Being able to interpret this
Element is not **REQUIRED** for playback. */
TimeSlice = 0xE8,
/** [uinteger] The reverse number of the frame in the lace (0 is the last frame, 1 is the next to last, etc). Being
able to interpret this Element is not **REQUIRED** for playback. */
LaceNumber = 0xCC,
/** [uinteger] The number of the frame to generate from this lace with this delay (allow you to generate many frames
from the same Block/Frame). */
FrameNumber = 0xCD,
/** [uinteger] The ID of the BlockAdditional Element (0 is the main Block). */
BlockAdditionID = 0xCB,
/** [uinteger] The (scaled) delay to apply to the Element. */
Delay = 0xCE,
/** [uinteger] The (scaled) duration to apply to the Element. */
SliceDuration = 0xCF,
/** [master] Contains information about the last reference frame. See [@?DivXTrickTrack]. */
ReferenceFrame = 0xC8,
/** [uinteger] The relative offset, in bytes, from the previous BlockGroup element for this Smooth FF/RW video track
to the containing BlockGroup element. See [@?DivXTrickTrack]. */
ReferenceOffset = 0xC9,
/** [uinteger] The timecode of the BlockGroup pointed to by ReferenceOffset. See [@?DivXTrickTrack]. */
ReferenceTimestamp = 0xCA,
/** [binary] Similar to SimpleBlock, see (#simpleblock-structure), but the data inside the Block are Transformed
(encrypt and/or signed). */
EncryptedBlock = 0xAF,
/** [master] A Top-Level Element of information with many tracks described. */
Tracks = 0x1654AE6B,
/** [master] Describes a track with all Elements. */
TrackEntry = 0xAE,
/** [uinteger] The track number as used in the Block Header (using more than 127 tracks is not encouraged, though
the design allows an unlimited number). */
TrackNumber = 0xD7,
/** [uinteger] A unique ID to identify the Track. */
TrackUID = 0x73C5,
/** [uinteger] The `TrackType` defines the type of each frame found in the Track. The value **SHOULD** be stored on
1 octet. */
TrackType = 0x83,
/** [uinteger] Set to 1 if the track is usable. It is possible to turn a not usable track into a usable track using
chapter codecs or control tracks. */
FlagEnabled = 0xB9,
/** [uinteger] Set if that track (audio, video or subs) **SHOULD** be eligible for automatic selection by the
player; see (#default-track-selection) for more details. */
FlagDefault = 0x88,
/** [uinteger] Applies only to subtitles. Set if that track **SHOULD** be eligible for automatic selection by the
player if it matches the user's language preference, even if the user's preferences would normally not enable
subtitles with the selected audio track; this can be used for tracks containing only translations of
foreign-language audio or onscreen text. See (#default-track-selection) for more details. */
FlagForced = 0x55AA,
/** [uinteger] Set to 1 if that track is suitable for users with hearing impairments, set to 0 if it is unsuitable
for users with hearing impairments. */
FlagHearingImpaired = 0x55AB,
/** [uinteger] Set to 1 if that track is suitable for users with visual impairments, set to 0 if it is unsuitable
for users with visual impairments. */
FlagVisualImpaired = 0x55AC,
/** [uinteger] Set to 1 if that track contains textual descriptions of video content, set to 0 if that track does
not contain textual descriptions of video content. */
FlagTextDescriptions = 0x55AD,
/** [uinteger] Set to 1 if that track is in the content's original language, set to 0 if it is a translation. */
FlagOriginal = 0x55AE,
/** [uinteger] Set to 1 if that track contains commentary, set to 0 if it does not contain commentary. */
FlagCommentary = 0x55AF,
/** [uinteger] Set to 1 if the track **MAY** contain blocks using lacing. When set to 0 all blocks **MUST** have
their lacing flags set to No lacing; see (#block-lacing) on Block Lacing. */
FlagLacing = 0x9C,
/** [uinteger] The minimum number of frames a player **SHOULD** be able to cache during playback. If set to 0, the
reference pseudo-cache system is not used. */
MinCache = 0x6DE7,
/** [uinteger] The maximum cache size necessary to store referenced frames in and the current frame. 0 means no
cache is needed. */
MaxCache = 0x6DF8,
/** [uinteger] Number of nanoseconds (not scaled via TimestampScale) per frame (frame in the Matroska sense -- one
Element put into a (Simple)Block). */
DefaultDuration = 0x23E383,
/** [uinteger] The period in nanoseconds (not scaled by TimestampScale) between two successive fields at the output
of the decoding process, see (#defaultdecodedfieldduration) for more information */
DefaultDecodedFieldDuration = 0x234E7A,
/** [float] DEPRECATED, DO NOT USE. The scale to apply on this track to work at normal speed in relation with other
tracks (mostly used to adjust video speed when the audio length differs). */
TrackTimestampScale = 0x23314F,
/** [integer] A value to add to the Block's Timestamp. This can be used to adjust the playback offset of a track. */
TrackOffset = 0x537F,
/** [uinteger] The maximum value of BlockAddID ((#blockaddid-element)). A value 0 means there is no BlockAdditions
((#blockadditions-element)) for this track. */
MaxBlockAdditionID = 0x55EE,
/** [master] Contains elements that extend the track format, by adding content either to each frame, with BlockAddID
((#blockaddid-element)), or to the track as a whole with BlockAddIDExtraData. */
BlockAdditionMapping = 0x41E4,
/** [uinteger] If the track format extension needs content beside frames, the value refers to the BlockAddID
((#blockaddid-element)), value being described. To keep MaxBlockAdditionID as low as possible, small values
**SHOULD** be used. */
BlockAddIDValue = 0x41F0,
/** [string] A human-friendly name describing the type of BlockAdditional data, as defined by the associated Block
Additional Mapping. */
BlockAddIDName = 0x41A4,
/** [uinteger] Stores the registered identifier of the Block Additional Mapping to define how the BlockAdditional
data should be handled. */
BlockAddIDType = 0x41E7,
/** [binary] Extra binary data that the BlockAddIDType can use to interpret the BlockAdditional data. The
interpretation of the binary data depends on the BlockAddIDType value and the corresponding Block Additional
Mapping. */
BlockAddIDExtraData = 0x41ED,
/** [utf-8] A human-readable track name. */
Name = 0x536E,
/** [string] Specifies the language of the track in the Matroska languages form; see (#language-codes) on language
codes. This Element **MUST** be ignored if the LanguageIETF Element is used in the same TrackEntry. */
Language = 0x22B59C,
/** [string] Specifies the language of the track according to [@!BCP47] and using the IANA Language Subtag Registry
[@!IANALangRegistry]. If this Element is used, then any Language Elements used in the same TrackEntry **MUST** be
ignored. */
LanguageIETF = 0x22B59D,
/** [string] An ID corresponding to the codec, see [@!MatroskaCodec] for more info. */
CodecID = 0x86,
/** [binary] Private data only known to the codec. */
CodecPrivate = 0x63A2,
/** [utf-8] A human-readable string specifying the codec. */
CodecName = 0x258688,
/** [uinteger] The UID of an attachment that is used by this codec. */
AttachmentLink = 0x7446,
/** [utf-8] A string describing the encoding setting used. */
CodecSettings = 0x3A9697,
/** [string] A URL to find information about the codec used. */
CodecInfoURL = 0x3B4040,
/** [string] A URL to download about the codec used. */
CodecDownloadURL = 0x26B240,
/** [uinteger] Set to 1 if the codec can decode potentially damaged data. */
CodecDecodeAll = 0xAA,
/** [uinteger] Specify that this track is an overlay track for the Track specified (in the u-integer). That means
when this track has a gap, see (#silenttracks-element) on SilentTracks, the overlay track **SHOULD** be used
instead. The order of multiple TrackOverlay matters, the first one is the one that **SHOULD** be used. If not
found it **SHOULD** be the second, etc. */
TrackOverlay = 0x6FAB,
/** [uinteger] CodecDelay is The codec-built-in delay in nanoseconds. This value **MUST** be subtracted from each
block timestamp in order to get the actual timestamp. The value **SHOULD** be small so the muxing of tracks with
the same actual timestamp are in the same Cluster. */
CodecDelay = 0x56AA,
/** [uinteger] After a discontinuity, SeekPreRoll is the duration in nanoseconds of the data the decoder **MUST**
decode before the decoded data is valid. */
SeekPreRoll = 0x56BB,
/** [master] The mapping between this `TrackEntry` and a track value in the given Chapter Codec. */
TrackTranslate = 0x6624,
/** [binary] The binary value used to represent this `TrackEntry` in the chapter codec data. The format depends on
the `ChapProcessCodecID` used; see (#chapprocesscodecid-element). */
TrackTranslateTrackID = 0x66A5,
/** [uinteger] This `TrackTranslate` applies to this chapter codec of the given chapter edition(s); see
(#chapprocesscodecid-element). */
TrackTranslateCodec = 0x66BF,
/** [uinteger] Specify a chapter edition UID on which this `TrackTranslate` applies. */
TrackTranslateEditionUID = 0x66FC,
/** [master] Video settings. */
Video = 0xE0,
/** [uinteger] Specify whether the video frames in this track are interlaced or not. */
FlagInterlaced = 0x9A,
/** [uinteger] Specify the field ordering of video frames in this track. */
FieldOrder = 0x9D,
/** [uinteger] Stereo-3D video mode. There are some more details in (#multi-planar-and-3d-videos). */
StereoMode = 0x53B8,
/** [uinteger] Alpha Video Mode. Presence of this Element indicates that the BlockAdditional Element could contain
Alpha data. */
AlphaMode = 0x53C0,
/** [uinteger] DEPRECATED, DO NOT USE. Bogus StereoMode value used in old versions of libmatroska. */
OldStereoMode = 0x53B9,
/** [uinteger] Width of the encoded video frames in pixels. */
PixelWidth = 0xB0,
/** [uinteger] Height of the encoded video frames in pixels. */
PixelHeight = 0xBA,
/** [uinteger] The number of video pixels to remove at the bottom of the image. */
PixelCropBottom = 0x54AA,
/** [uinteger] The number of video pixels to remove at the top of the image. */
PixelCropTop = 0x54BB,
/** [uinteger] The number of video pixels to remove on the left of the image. */
PixelCropLeft = 0x54CC,
/** [uinteger] The number of video pixels to remove on the right of the image. */
PixelCropRight = 0x54DD,
/** [uinteger] Width of the video frames to display. Applies to the video frame after cropping (PixelCrop*
Elements). */
DisplayWidth = 0x54B0,
/** [uinteger] Height of the video frames to display. Applies to the video frame after cropping (PixelCrop*
Elements). */
DisplayHeight = 0x54BA,
/** [uinteger] How DisplayWidth & DisplayHeight are interpreted. */
DisplayUnit = 0x54B2,
/** [uinteger] Specify the possible modifications to the aspect ratio. */
AspectRatioType = 0x54B3,
/** [binary] Specify the uncompressed pixel format used for the Track's data as a FourCC. This value is similar in
scope to the biCompression value of AVI's `BITMAPINFO` [@?AVIFormat]. See the YUV video formats [@?FourCC-YUV]
and RGB video formats [@?FourCC-RGB] for common values. */
UncompressedFourCC = 0x2EB524,
/** [float] Gamma Value. */
GammaValue = 0x2FB523,
/** [float] Number of frames per second. This value is Informational only. It is intended for constant frame rate
streams, and **SHOULD NOT** be used for a variable frame rate TrackEntry. */
FrameRate = 0x2383E3,
/** [master] Settings describing the colour format. */
Colour = 0x55B0,
/** [uinteger] The Matrix Coefficients of the video used to derive luma and chroma values from red, green, and blue
color primaries. For clarity, the value and meanings for MatrixCoefficients are adopted from Table 4 of ISO/IEC
23001-8:2016 or ITU-T H.273. */
MatrixCoefficients = 0x55B1,
/** [uinteger] Number of decoded bits per channel. A value of 0 indicates that the BitsPerChannel is unspecified. */
BitsPerChannel = 0x55B2,
/** [uinteger] The amount of pixels to remove in the Cr and Cb channels for every pixel not removed horizontally.
Example: For video with 4:2:0 chroma subsampling, the ChromaSubsamplingHorz **SHOULD** be set to 1. */
ChromaSubsamplingHorz = 0x55B3,
/** [uinteger] The amount of pixels to remove in the Cr and Cb channels for every pixel not removed vertically.
Example: For video with 4:2:0 chroma subsampling, the ChromaSubsamplingVert **SHOULD** be set to 1. */
ChromaSubsamplingVert = 0x55B4,
/** [uinteger] The amount of pixels to remove in the Cb channel for every pixel not removed horizontally. This is
additive with ChromaSubsamplingHorz. Example: For video with 4:2:1 chroma subsampling, the ChromaSubsamplingHorz
**SHOULD** be set to 1 and CbSubsamplingHorz **SHOULD** be set to 1. */
CbSubsamplingHorz = 0x55B5,
/** [uinteger] The amount of pixels to remove in the Cb channel for every pixel not removed vertically. This is
additive with ChromaSubsamplingVert. */
CbSubsamplingVert = 0x55B6,
/** [uinteger] How chroma is subsampled horizontally. */
ChromaSitingHorz = 0x55B7,
/** [uinteger] How chroma is subsampled vertically. */
ChromaSitingVert = 0x55B8,
/** [uinteger] Clipping of the color ranges. */
Range = 0x55B9,
/** [uinteger] The transfer characteristics of the video. For clarity, the value and meanings for
TransferCharacteristics are adopted from Table 3 of ISO/IEC 23091-4 or ITU-T H.273. */
TransferCharacteristics = 0x55BA,
/** [uinteger] The colour primaries of the video. For clarity, the value and meanings for Primaries are adopted from
Table 2 of ISO/IEC 23091-4 or ITU-T H.273. */
Primaries = 0x55BB,
/** [uinteger] Maximum brightness of a single pixel (Maximum Content Light Level) in candelas per square meter
(cd/m^2^). */
MaxCLL = 0x55BC,
/** [uinteger] Maximum brightness of a single full frame (Maximum Frame-Average Light Level) in candelas per square
meter (cd/m^2^). */
MaxFALL = 0x55BD,
/** [master] SMPTE 2086 mastering data. */
MasteringMetadata = 0x55D0,
/** [float] Red X chromaticity coordinate, as defined by CIE 1931. */
PrimaryRChromaticityX = 0x55D1,
/** [float] Red Y chromaticity coordinate, as defined by CIE 1931. */
PrimaryRChromaticityY = 0x55D2,
/** [float] Green X chromaticity coordinate, as defined by CIE 1931. */
PrimaryGChromaticityX = 0x55D3,
/** [float] Green Y chromaticity coordinate, as defined by CIE 1931. */
PrimaryGChromaticityY = 0x55D4,
/** [float] Blue X chromaticity coordinate, as defined by CIE 1931. */
PrimaryBChromaticityX = 0x55D5,
/** [float] Blue Y chromaticity coordinate, as defined by CIE 1931. */
PrimaryBChromaticityY = 0x55D6,
/** [float] White X chromaticity coordinate, as defined by CIE 1931. */
WhitePointChromaticityX = 0x55D7,
/** [float] White Y chromaticity coordinate, as defined by CIE 1931. */
WhitePointChromaticityY = 0x55D8,
/** [float] Maximum luminance. Represented in candelas per square meter (cd/m^2^). */
LuminanceMax = 0x55D9,
/** [float] Minimum luminance. Represented in candelas per square meter (cd/m^2^). */
LuminanceMin = 0x55DA,
/** [master] Describes the video projection details. Used to render spherical, VR videos or flipping videos
horizontally/vertically. */
Projection = 0x7670,
/** [uinteger] Describes the projection used for this video track. */
ProjectionType = 0x7671,
/** [binary] Private data that only applies to a specific projection. * If `ProjectionType` equals 0
(Rectangular), then this element must not be present. * If `ProjectionType` equals 1 (Equirectangular),
then this element must be present and contain the same binary data that would be stored inside an ISOBMFF
Equirectangular Projection Box ('equi'). * If `ProjectionType` equals 2 (Cubemap), then this element must be
present and contain the same binary data that would be stored inside an ISOBMFF Cubemap Projection Box
('cbmp'). * If `ProjectionType` equals 3 (Mesh), then this element must be present and contain the same binary
data that would be stored inside an ISOBMFF Mesh Projection Box ('mshp'). */
ProjectionPrivate = 0x7672,
/** [float] Specifies a yaw rotation to the projection. Value represents a clockwise rotation, in degrees, around
the up vector. This rotation must be applied before any `ProjectionPosePitch` or `ProjectionPoseRoll` rotations.
The value of this element **MUST** be in the -180 to 180 degree range, both included. Setting
`ProjectionPoseYaw` to 180 or -180 degrees, with the `ProjectionPoseRoll` and `ProjectionPosePitch` set to 0
degrees flips the image horizontally. */
ProjectionPoseYaw = 0x7673,
/** [float] Specifies a pitch rotation to the projection. Value represents a counter-clockwise rotation, in
degrees, around the right vector. This rotation must be applied after the `ProjectionPoseYaw` rotation and before
the `ProjectionPoseRoll` rotation. The value of this element **MUST** be in the -90 to 90 degree range, both
included. */
ProjectionPosePitch = 0x7674,
/** [float] Specifies a roll rotation to the projection. Value represents a counter-clockwise rotation, in degrees,
around the forward vector. This rotation must be applied after the `ProjectionPoseYaw` and `ProjectionPosePitch`
rotations. The value of this element **MUST** be in the -180 to 180 degree range, both included. Setting
`ProjectionPoseRoll` to 180 or -180 degrees, the `ProjectionPoseYaw` to 180 or -180 degrees with
`ProjectionPosePitch` set to 0 degrees flips the image vertically. Setting `ProjectionPoseRoll` to 180 or -180
degrees, with the `ProjectionPoseYaw` and `ProjectionPosePitch` set to 0 degrees flips the image horizontally and
vertically. */
ProjectionPoseRoll = 0x7675,
/** [master] Audio settings. */
Audio = 0xE1,
/** [float] Sampling frequency in Hz. */
SamplingFrequency = 0xB5,
/** [float] Real output sampling frequency in Hz (used for SBR techniques). */
OutputSamplingFrequency = 0x78B5,
/** [uinteger] Numbers of channels in the track. */
Channels = 0x9F,
/** [binary] Table of horizontal angles for each successive channel. */
ChannelPositions = 0x7D7B,
/** [uinteger] Bits per sample, mostly used for PCM. */
BitDepth = 0x6264,
/** [master] Operation that needs to be applied on tracks to create this virtual track. For more details look at
(#track-operation). */
TrackOperation = 0xE2,
/** [master] Contains the list of all video plane tracks that need to be combined to create this 3D track */
TrackCombinePlanes = 0xE3,
/** [master] Contains a video plane track that need to be combined to create this 3D track */
TrackPlane = 0xE4,
/** [uinteger] The trackUID number of the track representing the plane. */
TrackPlaneUID = 0xE5,
/** [uinteger] The kind of plane this track corresponds to. */
TrackPlaneType = 0xE6,
/** [master] Contains the list of all tracks whose Blocks need to be combined to create this virtual track */
TrackJoinBlocks = 0xE9,
/** [uinteger] The trackUID number of a track whose blocks are used to create this virtual track. */
TrackJoinUID = 0xED,
/** [uinteger] The TrackUID of the Smooth FF/RW video in the paired EBML structure corresponding to this video
track. See [@?DivXTrickTrack]. */
TrickTrackUID = 0xC0,
/** [binary] The SegmentUID of the Segment containing the track identified by TrickTrackUID. See [@?DivXTrickTrack].
*/
TrickTrackSegmentUID = 0xC1,
/** [uinteger] Set to 1 if this video track is a Smooth FF/RW track. If set to 1, MasterTrackUID and
MasterTrackSegUID should must be present and BlockGroups for this track must contain ReferenceFrame structures.
Otherwise, TrickTrackUID and TrickTrackSegUID must be present if this track has a corresponding Smooth FF/RW
track. See [@?DivXTrickTrack]. */
TrickTrackFlag = 0xC6,
/** [uinteger] The TrackUID of the video track in the paired EBML structure that corresponds to this Smooth FF/RW
track. See [@?DivXTrickTrack]. */
TrickMasterTrackUID = 0xC7,
/** [binary] The SegmentUID of the Segment containing the track identified by MasterTrackUID. See
[@?DivXTrickTrack]. */
TrickMasterTrackSegmentUID = 0xC4,
/** [master] Settings for several content encoding mechanisms like compression or encryption. */
ContentEncodings = 0x6D80,
/** [master] Settings for one content encoding like compression or encryption. */
ContentEncoding = 0x6240,
/** [uinteger] Tells when this modification was used during encoding/muxing starting with 0 and counting upwards.
The decoder/demuxer has to start with the highest order number it finds and work its way down. This value has to
be unique over all ContentEncodingOrder Elements in the TrackEntry that contains this ContentEncodingOrder
element. */
ContentEncodingOrder = 0x5031,
/** [uinteger] A bit field that describes which Elements have been modified in this way. Values (big-endian) can be
OR'ed. */
ContentEncodingScope = 0x5032,
/** [uinteger] A value describing what kind of transformation is applied. */
ContentEncodingType = 0x5033,
/** [master] Settings describing the compression used. This Element **MUST** be present if the value of
ContentEncodingType is 0 and absent otherwise. Each block **MUST** be decompressable even if no previous block is
available in order not to prevent seeking. */
ContentCompression = 0x5034,
/** [uinteger] The compression algorithm used. */
ContentCompAlgo = 0x4254,
/** [binary] Settings that might be needed by the decompressor. For Header Stripping (`ContentCompAlgo`=3), the
bytes that were removed from the beginning of each frames of the track. */
ContentCompSettings = 0x4255,
/** [master] Settings describing the encryption used. This Element **MUST** be present if the value of
`ContentEncodingType` is 1 (encryption) and **MUST** be ignored otherwise. */
ContentEncryption = 0x5035,
/** [uinteger] The encryption algorithm used. The value "0" means that the contents have not been encrypted. */
ContentEncAlgo = 0x47E1,
/** [binary] For public key algorithms this is the ID of the public key the the data was encrypted with. */
ContentEncKeyID = 0x47E2,
/** [master] Settings describing the encryption algorithm used. If `ContentEncAlgo` != 5 this **MUST** be ignored.
*/
ContentEncAESSettings = 0x47E7,
/** [uinteger] The AES cipher mode used in the encryption. */
AESSettingsCipherMode = 0x47E8,
/** [binary] A cryptographic signature of the contents. */
ContentSignature = 0x47E3,
/** [binary] This is the ID of the private key the data was signed with. */
ContentSigKeyID = 0x47E4,
/** [uinteger] The algorithm used for the signature. */
ContentSigAlgo = 0x47E5,
/** [uinteger] The hash algorithm used for the signature. */
ContentSigHashAlgo = 0x47E6,
/** [master] A Top-Level Element to speed seeking access. All entries are local to the Segment. */
Cues = 0x1C53BB6B,
/** [master] Contains all information relative to a seek point in the Segment. */
CuePoint = 0xBB,
/** [uinteger] Absolute timestamp according to the Segment time base. */
CueTime = 0xB3,
/** [master] Contain positions for different tracks corresponding to the timestamp. */
CueTrackPositions = 0xB7,
/** [uinteger] The track for which a position is given. */
CueTrack = 0xF7,
/** [uinteger] The Segment Position of the Cluster containing the associated Block. */
CueClusterPosition = 0xF1,
/** [uinteger] The relative position inside the Cluster of the referenced SimpleBlock or BlockGroup with 0 being the
first possible position for an Element inside that Cluster. */
CueRelativePosition = 0xF0,
/** [uinteger] The duration of the block according to the Segment time base. If missing the track's DefaultDuration
does not apply and no duration information is available in terms of the cues. */
CueDuration = 0xB2,
/** [uinteger] Number of the Block in the specified Cluster. */
CueBlockNumber = 0x5378,
/** [uinteger] The Segment Position of the Codec State corresponding to this Cue Element. 0 means that the data is
taken from the initial Track Entry. */
CueCodecState = 0xEA,
/** [master] The Clusters containing the referenced Blocks. */
CueReference = 0xDB,
/** [uinteger] Timestamp of the referenced Block. */
CueRefTime = 0x96,
/** [uinteger] The Segment Position of the Cluster containing the referenced Block. */
CueRefCluster = 0x97,
/** [uinteger] Number of the referenced Block of Track X in the specified Cluster. */
CueRefNumber = 0x535F,
/** [uinteger] The Segment Position of the Codec State corresponding to this referenced Element. 0 means that the
data is taken from the initial Track Entry. */
CueRefCodecState = 0xEB,
/** [master] Contain attached files. */
Attachments = 0x1941A469,
/** [master] An attached file. */
AttachedFile = 0x61A7,
/** [utf-8] A human-friendly name for the attached file. */
FileDescription = 0x467E,
/** [utf-8] Filename of the attached file. */
FileName = 0x466E,
/** [string] MIME type of the file. */
FileMimeType = 0x4660,
/** [binary] The data of the file. */
FileData = 0x465C,
/** [uinteger] Unique ID representing the file, as random as possible. */
FileUID = 0x46AE,
/** [binary] A binary value that a track/codec can refer to when the attachment is needed. */
FileReferral = 0x4675,
/** [uinteger] The timecode at which this optimized font attachment comes into context, based on the Segment
TimecodeScale. This element is reserved for future use and if written must be the segment start time. See
[@?DivXWorldFonts]. */
FileUsedStartTime = 0x4661,
/** [uinteger] The timecode at which this optimized font attachment goes out of context, based on the Segment
TimecodeScale. This element is reserved for future use and if written must be the segment end time. See
[@?DivXWorldFonts]. */
FileUsedEndTime = 0x4662,
/** [master] A system to define basic menus and partition data. For more detailed information, look at the Chapters
explanation in (#chapters). */
Chapters = 0x1043A770,
/** [master] Contains all information about a Segment edition. */
EditionEntry = 0x45B9,
/** [uinteger] A unique ID to identify the edition. It's useful for tagging an edition. */
EditionUID = 0x45BC,
/** [uinteger] Set to 1 if an edition is hidden. Hidden editions **SHOULD NOT** be available to the user interface
(but still to Control Tracks; see (#chapter-flags) on Chapter flags). */
EditionFlagHidden = 0x45BD,
/** [uinteger] Set to 1 if the edition **SHOULD** be used as the default one. */
EditionFlagDefault = 0x45DB,
/** [uinteger] Set to 1 if the chapters can be defined multiple times and the order to play them is enforced; see
(#editionflagordered). */
EditionFlagOrdered = 0x45DD,
/** [master] Contains the atom information to use as the chapter atom (apply to all tracks). */
ChapterAtom = 0xB6,
/** [uinteger] A unique ID to identify the Chapter. */
ChapterUID = 0x73C4,
/** [utf-8] A unique string ID to identify the Chapter. Use for WebVTT cue identifier storage [@!WebVTT]. */
ChapterStringUID = 0x5654,
/** [uinteger] Timestamp of the start of Chapter (not scaled). */
ChapterTimeStart = 0x91,
/** [uinteger] Timestamp of the end of Chapter (timestamp excluded, not scaled). The value **MUST** be greater than
or equal to the `ChapterTimeStart` of the same `ChapterAtom`. */
ChapterTimeEnd = 0x92,
/** [uinteger] Set to 1 if a chapter is hidden. Hidden chapters **SHOULD NOT** be available to the user interface
(but still to Control Tracks; see (#chapterflaghidden) on Chapter flags). */
ChapterFlagHidden = 0x98,
/** [uinteger] Set to 1 if the chapter is enabled. It can be enabled/disabled by a Control Track. When disabled, the
movie **SHOULD** skip all the content between the TimeStart and TimeEnd of this chapter; see (#chapter-flags) on
Chapter flags. */
ChapterFlagEnabled = 0x4598,
/** [binary] The SegmentUID of another Segment to play during this chapter. */
ChapterSegmentUID = 0x6E67,
/** [uinteger] The EditionUID to play from the Segment linked in ChapterSegmentUID. If ChapterSegmentEditionUID is
undeclared, then no Edition of the linked Segment is used; see (#medium-linking) on medium-linking Segments. */
ChapterSegmentEditionUID = 0x6EBC,
/** [uinteger] Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50); see
(#physical-types) for a complete list of values. */
ChapterPhysicalEquiv = 0x63C3,
/** [master] List of tracks on which the chapter applies. If this Element is not present, all tracks apply */
ChapterTrack = 0x8F,
/** [uinteger] UID of the Track to apply this chapter to. In the absence of a control track, choosing this chapter
will select the listed Tracks and deselect unlisted tracks. Absence of this Element indicates that the Chapter
**SHOULD** be applied to any currently used Tracks. */
ChapterTrackUID = 0x89,
/** [master] Contains all possible strings to use for the chapter display. */
ChapterDisplay = 0x80,
/** [utf-8] Contains the string to use as the chapter atom. */
ChapString = 0x85,
/** [string] A language corresponding to the string, in the bibliographic ISO-639-2 form [@!ISO639-2]. This Element
**MUST** be ignored if a ChapLanguageIETF Element is used within the same ChapterDisplay Element. */
ChapLanguage = 0x437C,
/** [string] Specifies a language corresponding to the ChapString in the format defined in [@!BCP47] and using the
IANA Language Subtag Registry [@!IANALangRegistry]. If a ChapLanguageIETF Element is used, then any ChapLanguage
and ChapCountry Elements used in the same ChapterDisplay **MUST** be ignored. */
ChapLanguageIETF = 0x437D,
/** [string] A country corresponding to the string, using the same 2 octets country-codes as in Internet domains
[@!IANADomains] based on [@!ISO3166-1] alpha-2 codes. This Element **MUST** be ignored if a ChapLanguageIETF
Element is used within the same ChapterDisplay Element. */
ChapCountry = 0x437E,
/** [master] Contains all the commands associated to the Atom. */
ChapProcess = 0x6944,
/** [uinteger] Contains the type of the codec used for the processing. A value of 0 means native Matroska processing
(to be defined), a value of 1 means the DVD command set is used; see (#menu-features) on DVD menus. More codec
IDs can be added later. */
ChapProcessCodecID = 0x6955,
/** [binary] Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it
is the "DVD level" equivalent; see (#menu-features) on DVD menus. */
ChapProcessPrivate = 0x450D,
/** [master] Contains all the commands associated to the Atom. */
ChapProcessCommand = 0x6911,
/** [uinteger] Defines when the process command **SHOULD** be handled */
ChapProcessTime = 0x6922,
/** [binary] Contains the command information. The data **SHOULD** be interpreted depending on the
ChapProcessCodecID value. For ChapProcessCodecID = 1, the data correspond to the binary DVD cell pre/post
commands; see (#menu-features) on DVD menus. */
ChapProcessData = 0x6933,
/** [master] Element containing metadata describing Tracks, Editions, Chapters, Attachments, or the Segment as a
whole. A list of valid tags can be found in [@!MatroskaTags]. */
Tags = 0x1254C367,
/** [master] A single metadata descriptor. */
Tag = 0x7373,
/** [master] Specifies which other elements the metadata represented by the Tag applies to. If empty or not present,
then the Tag describes everything in the Segment. */
Targets = 0x63C0,
/** [uinteger] A number to indicate the logical level of the target. */
TargetTypeValue = 0x68CA,
/** [string] An informational string that can be used to display the logical level of the target like "ALBUM",
"TRACK", "MOVIE", "CHAPTER", etc ; see Section 6.4 of [@!MatroskaTags]. */
TargetType = 0x63CA,
/** [uinteger] A unique ID to identify the Track(s) the tags belong to. */
TagTrackUID = 0x63C5,
/** [uinteger] A unique ID to identify the EditionEntry(s) the tags belong to. */
TagEditionUID = 0x63C9,
/** [uinteger] A unique ID to identify the Chapter(s) the tags belong to. */
TagChapterUID = 0x63C4,
/** [uinteger] A unique ID to identify the Attachment(s) the tags belong to. */
TagAttachmentUID = 0x63C6,
/** [master] Contains general information about the target. */
SimpleTag = 0x67C8,
/** [utf-8] The name of the Tag that is going to be stored. */
TagName = 0x45A3,
/** [string] Specifies the language of the tag specified, in the Matroska languages form; see (#language-codes) on
language codes. This Element **MUST** be ignored if the TagLanguageIETF Element is used within the same SimpleTag
Element. */
TagLanguage = 0x447A,
/** [string] Specifies the language used in the TagString according to [@!BCP47] and using the IANA Language Subtag
Registry [@!IANALangRegistry]. If this Element is used, then any TagLanguage Elements used in the same SimpleTag
**MUST** be ignored. */
TagLanguageIETF = 0x447B,
/** [uinteger] A boolean value to indicate if this is the default/original language to use for the given tag. */
TagDefault = 0x4484,
/** [uinteger] A variant of the TagDefault element with a bogus Element ID; see (#tagdefault-element). */
TagDefaultBogus = 0x44B4,
/** [utf-8] The value of the Tag. */
TagString = 0x4487,
/** [binary] The values of the Tag, if it is binary. Note that this cannot be used in the same SimpleTag as
TagString. */
TagBinary = 0x4485,
};

View File

@@ -0,0 +1,27 @@
#ifndef ES8311AUDIOSINK_H
#define ES8311AUDIOSINK_H
#include "driver/i2s.h"
#include <vector>
#include <iostream>
#include "BufferedAudioSink.h"
#include <stdio.h>
#include <string.h>
#include "driver/gpio.h"
#include "driver/i2c.h"
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
class ES8311AudioSink : public BufferedAudioSink
{
public:
ES8311AudioSink();
~ES8311AudioSink();
void writeReg(uint8_t reg_add, uint8_t data);
void volumeChanged(uint16_t volume);
private:
};
#endif

View File

@@ -0,0 +1,121 @@
/*
* ES8311.h -- ES8311 ALSA SoC Audio Codec
*
* Authors:
*
* Based on ES8374.h by David Yang
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ES8311_H
#define _ES8311_H
#include "driver/i2c.h"
#include "esxxx_common.h"
/*
* ES8311_REGISTER NAME_REG_REGISTER ADDRESS
*/
#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/
/*
* Clock Scheme Register definition
*/
#define ES8311_CLK_MANAGER_REG01 0x01 /* select clk src for mclk, enable clock for codec */
#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */
#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */
#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */
#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */
#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */
#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */
#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */
#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */
#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */
#define ES8311_SYSTEM_REG0B 0x0B /* system */
#define ES8311_SYSTEM_REG0C 0x0C /* system */
#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */
#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */
#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */
#define ES8311_SYSTEM_REG10 0x10 /* system */
#define ES8311_SYSTEM_REG11 0x11 /* system */
#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */
#define ES8311_SYSTEM_REG13 0x13 /* system */
#define ES8311_SYSTEM_REG14 0x14 /* system, select DMIC, select analog pga gain */
#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */
#define ES8311_ADC_REG16 0x16 /* ADC */
#define ES8311_ADC_REG17 0x17 /* ADC, volume */
#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */
#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */
#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */
#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */
#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */
#define ES8311_DAC_REG31 0x31 /* DAC, mute */
#define ES8311_DAC_REG32 0x32 /* DAC, volume */
#define ES8311_DAC_REG33 0x33 /* DAC, offset */
#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */
#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */
#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */
#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */
#define ES8311_GP_REG45 0x45 /* GP CONTROL */
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */
#define ES8311_CHVER_REGFF 0xFF /* VERSION */
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_MAX_REGISTER 0xFF
typedef struct {
ESCodecMode esMode;
i2c_port_t i2c_port_num;
i2c_config_t i2c_cfg;
DacOutput dacOutput;
AdcInput adcInput;
} Es8311Config;
#define AUDIO_CODEC_ES8311_DEFAULT(){ \
.esMode = ES_MODE_SLAVE, \
.i2c_port_num = I2C_NUM_0, \
.i2c_cfg = { \
.mode = I2C_MODE_MASTER, \
.sda_io_num = IIC_DATA, \
.scl_io_num = IIC_CLK, \
.sda_pullup_en = GPIO_PULLUP_ENABLE,\
.scl_pullup_en = GPIO_PULLUP_ENABLE,\
.master.clk_speed = 100000\
}, \
.adcInput = ADC_INPUT_LINPUT1_RINPUT1,\
.dacOutput = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1 | DAC_OUTPUT_ROUT2,\
};
int Es8311Init(Es8311Config *cfg);
void Es8311Uninit();
esp_err_t Es8311GetRef(bool flag);
esp_err_t Es7243Init(void);
int Es7243ReadReg(uint8_t regAdd);
int Es8311ConfigFmt(ESCodecModule mode, ESCodecI2SFmt fmt);
int Es8311I2sConfigClock(ESCodecI2sClock cfg);
int Es8311SetBitsPerSample(ESCodecModule mode, BitsLength bitPerSample);
int Es8311Start(ESCodecModule mode);
int Es8311Stop(ESCodecModule mode);
int Es8311SetVoiceVolume(int volume);
int Es8311GetVoiceVolume(int *volume);
int Es8311SetVoiceMute(int enable);
int Es8311GetVoiceMute(int *mute);
int Es8311SetMicGain(MicGain gain);
int Es8311ConfigAdcInput(AdcInput input);
int Es8311ConfigDacOutput(DacOutput output);
int ES8311WriteReg(uint8_t regAdd, uint8_t data);
void Es8311ReadAll();
int Es8311ReadReg(uint8_t regAdd);
#endif

View File

@@ -0,0 +1,166 @@
#ifndef __ESCODEC_COMMON_H__
#define __ESCODEC_COMMON_H__
typedef enum BitsLength {
BIT_LENGTH_MIN = -1,
BIT_LENGTH_16BITS = 0x03,
BIT_LENGTH_18BITS = 0x02,
BIT_LENGTH_20BITS = 0x01,
BIT_LENGTH_24BITS = 0x00,
BIT_LENGTH_32BITS = 0x04,
BIT_LENGTH_MAX,
} BitsLength;
typedef enum {
SAMPLE_RATE_MIN = -1,
SAMPLE_RATE_16K,
SAMPLE_RATE_32K,
SAMPLE_RATE_44_1K,
SAMPLE_RATE_MAX,
} SampleRate;
typedef enum {
MclkDiv_MIN = -1,
MclkDiv_1 = 1,
MclkDiv_2 = 2,
MclkDiv_3 = 3,
MclkDiv_4 = 4,
MclkDiv_6 = 5,
MclkDiv_8 = 6,
MclkDiv_9 = 7,
MclkDiv_11 = 8,
MclkDiv_12 = 9,
MclkDiv_16 = 10,
MclkDiv_18 = 11,
MclkDiv_22 = 12,
MclkDiv_24 = 13,
MclkDiv_33 = 14,
MclkDiv_36 = 15,
MclkDiv_44 = 16,
MclkDiv_48 = 17,
MclkDiv_66 = 18,
MclkDiv_72 = 19,
MclkDiv_5 = 20,
MclkDiv_10 = 21,
MclkDiv_15 = 22,
MclkDiv_17 = 23,
MclkDiv_20 = 24,
MclkDiv_25 = 25,
MclkDiv_30 = 26,
MclkDiv_32 = 27,
MclkDiv_34 = 28,
MclkDiv_7 = 29,
MclkDiv_13 = 30,
MclkDiv_14 = 31,
MclkDiv_MAX,
} SclkDiv;
typedef enum {
LclkDiv_MIN = -1,
LclkDiv_128 = 0,
LclkDiv_192 = 1,
LclkDiv_256 = 2,
LclkDiv_384 = 3,
LclkDiv_512 = 4,
LclkDiv_576 = 5,
LclkDiv_768 = 6,
LclkDiv_1024 = 7,
LclkDiv_1152 = 8,
LclkDiv_1408 = 9,
LclkDiv_1536 = 10,
LclkDiv_2112 = 11,
LclkDiv_2304 = 12,
LclkDiv_125 = 16,
LclkDiv_136 = 17,
LclkDiv_250 = 18,
LclkDiv_272 = 19,
LclkDiv_375 = 20,
LclkDiv_500 = 21,
LclkDiv_544 = 22,
LclkDiv_750 = 23,
LclkDiv_1000 = 24,
LclkDiv_1088 = 25,
LclkDiv_1496 = 26,
LclkDiv_1500 = 27,
LclkDiv_MAX,
} LclkDiv;
typedef enum {
ADC_INPUT_MIN = -1,
ADC_INPUT_LINPUT1_RINPUT1 = 0x00,
ADC_INPUT_MIC1 = 0x05,
ADC_INPUT_MIC2 = 0x06,
ADC_INPUT_LINPUT2_RINPUT2 = 0x50,
ADC_INPUT_DIFFERENCE = 0xf0,
ADC_INPUT_MAX,
} AdcInput;
typedef enum {
DAC_OUTPUT_MIN = -1,
DAC_OUTPUT_LOUT1 = 0x04,
DAC_OUTPUT_LOUT2 = 0x08,
DAC_OUTPUT_SPK = 0x09,
DAC_OUTPUT_ROUT1 = 0x10,
DAC_OUTPUT_ROUT2 = 0x20,
DAC_OUTPUT_ALL = 0x3c,
DAC_OUTPUT_MAX,
} DacOutput;
typedef enum {
D2SE_PGA_GAIN_MIN = -1,
D2SE_PGA_GAIN_DIS = 0,
D2SE_PGA_GAIN_EN = 1,
D2SE_PGA_GAIN_MAX = 2,
} D2SEPGA;
typedef enum {
MIC_GAIN_MIN = -1,
MIC_GAIN_0DB = 0,
MIC_GAIN_3DB = 3,
MIC_GAIN_6DB = 6,
MIC_GAIN_9DB = 9,
MIC_GAIN_12DB = 12,
MIC_GAIN_15DB = 15,
MIC_GAIN_18DB = 18,
MIC_GAIN_21DB = 21,
MIC_GAIN_24DB = 24,
#if defined CONFIG_CODEC_CHIP_IS_ES8311
MIC_GAIN_30DB = 30,
MIC_GAIN_36DB = 36,
MIC_GAIN_42DB = 42,
#endif
MIC_GAIN_MAX,
} MicGain;
typedef enum {
ES_MODULE_MIN = -1,
ES_MODULE_ADC = 0x01,
ES_MODULE_DAC = 0x02,
ES_MODULE_ADC_DAC = 0x03,
ES_MODULE_LINE = 0x04,
ES_MODULE_MAX
} ESCodecModule;
typedef enum {
ES_MODE_MIN = -1,
ES_MODE_SLAVE = 0x00,
ES_MODE_MASTER = 0x01,
ES_MODE_MAX,
} ESCodecMode;
typedef enum {
ES_ = -1,
ES_I2S_NORMAL = 0,
ES_I2S_LEFT = 1,
ES_I2S_RIGHT = 2,
ES_I2S_DSP = 3,
ES_I2S_MAX
} ESCodecI2SFmt;
typedef struct {
SclkDiv sclkDiv;
LclkDiv lclkDiv;
} ESCodecI2sClock;
#endif //__ESCODEC_COMMON_H__

View File

@@ -5,7 +5,7 @@
#include "AudioSink.h"
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <Task.h>
#include <BellTask.h>
#include <unistd.h>
#include <memory>
#include <mutex>

View File

@@ -0,0 +1,18 @@
#ifndef BELLL_MDNS_SERVICE_H
#define BELLL_MDNS_SERVICE_H
#include <string>
#include <map>
class MDNSService {
public:
static void registerService(
const std::string &serviceName,
const std::string &serviceType,
const std::string &serviceProto,
const std::string &serviceHost,
int servicePort,
const std::map<std::string, std::string> txtData
);
};
#endif

View File

@@ -6,6 +6,8 @@
#include "freertos/semphr.h"
#elif __APPLE__
#include <dispatch/dispatch.h>
#elif _WIN32
#include <winsock2.h>
#else
#include <time.h>
#include <semaphore.h>
@@ -18,6 +20,8 @@ private:
xSemaphoreHandle semaphoreHandle;
#elif __APPLE__
dispatch_semaphore_t semaphoreHandle;
#elif _WIN32
HANDLE semaphoreHandle;
#else
sem_t semaphoreHandle;
#endif

View File

@@ -0,0 +1,15 @@
#pragma once
#include <winsock2.h>
#define SHUT_RDWR SD_BOTH
#define ssize_t SSIZE_T
#define strcasecmp stricmp
#define strncasecmp _strnicmp
#define bzero(p,n) memset(p,0,n)
#define usleep(x) Sleep((x)/1000)
inline void close(int sock) { closesocket(sock); }
inline size_t read(int sock, char* buf, size_t n) { return recv(sock, buf, n, 0); }
inline int write(int sock, const char* buf, size_t n) { return send(sock, buf, n, 0); }