mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-22 07:28:31 +03:00
Bell catchup
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
#include "AACDecoder.h"
|
||||
|
||||
#include <stdlib.h> // for free, malloc
|
||||
|
||||
#include "CodecType.h" // for bell
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "e_tmp4audioobjecttype.h"
|
||||
#include "pvmp4audiodecoder_api.h"
|
||||
|
||||
namespace bell {
|
||||
class AudioContainer;
|
||||
@@ -11,47 +13,100 @@ class AudioContainer;
|
||||
using namespace bell;
|
||||
|
||||
AACDecoder::AACDecoder() {
|
||||
aac = AACInitDecoder();
|
||||
pcmData = (int16_t*)malloc(AAC_MAX_NSAMPS * AAC_MAX_NCHANS * sizeof(int16_t));
|
||||
aacDecoder =
|
||||
(tPVMP4AudioDecoderExternal*)malloc(sizeof(tPVMP4AudioDecoderExternal));
|
||||
|
||||
int32_t pMemRequirement = PVMP4AudioDecoderGetMemRequirements();
|
||||
pMem = malloc(pMemRequirement);
|
||||
memset(aacDecoder, 0, sizeof(tPVMP4AudioDecoderExternal));
|
||||
memset(pMem, 0, pMemRequirement);
|
||||
|
||||
// Initialize the decoder buffers
|
||||
outputBuffer.resize(4096);
|
||||
|
||||
aacDecoder->pOutputBuffer_plus = &outputBuffer[2048];
|
||||
aacDecoder->pOutputBuffer = &outputBuffer[0];
|
||||
aacDecoder->inputBufferMaxLength = PVMP4AUDIODECODER_INBUFSIZE;
|
||||
|
||||
// Settings
|
||||
aacDecoder->desiredChannels = 2;
|
||||
aacDecoder->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
|
||||
aacDecoder->aacPlusEnabled = TRUE;
|
||||
|
||||
// State
|
||||
aacDecoder->inputBufferCurrentLength = 0;
|
||||
aacDecoder->inputBufferUsedLength = 0;
|
||||
aacDecoder->remainderBits = 0;
|
||||
|
||||
firstFrame = true;
|
||||
|
||||
assert(PVMP4AudioDecoderInitLibrary(aacDecoder, pMem) == MP4AUDEC_SUCCESS);
|
||||
}
|
||||
|
||||
AACDecoder::~AACDecoder() {
|
||||
AACFreeDecoder(aac);
|
||||
free(pcmData);
|
||||
free(pMem);
|
||||
free(aacDecoder);
|
||||
}
|
||||
|
||||
int AACDecoder::getDecodedStreamType() {
|
||||
switch (aacDecoder->extendedAudioObjectType) {
|
||||
case MP4AUDIO_AAC_LC:
|
||||
case MP4AUDIO_LTP:
|
||||
return AAC;
|
||||
case MP4AUDIO_SBR:
|
||||
return AACPLUS;
|
||||
case MP4AUDIO_PS:
|
||||
return ENH_AACPLUS;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool AACDecoder::setup(uint32_t sampleRate, uint8_t channelCount,
|
||||
uint8_t bitDepth) {
|
||||
PVMP4AudioDecoderResetBuffer(pMem);
|
||||
assert(PVMP4AudioDecoderInitLibrary(aacDecoder, pMem) == MP4AUDEC_SUCCESS);
|
||||
firstFrame = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AACDecoder::setup(AudioContainer* container) {
|
||||
PVMP4AudioDecoderResetBuffer(pMem);
|
||||
assert(PVMP4AudioDecoderInitLibrary(aacDecoder, pMem) == MP4AUDEC_SUCCESS);
|
||||
firstFrame = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* AACDecoder::decode(uint8_t* inData, uint32_t& inLen,
|
||||
uint32_t& outLen) {
|
||||
if (!inData)
|
||||
if (!inData || inLen == 0)
|
||||
return nullptr;
|
||||
|
||||
int status = AACDecode(aac, static_cast<unsigned char**>(&inData),
|
||||
reinterpret_cast<int*>(&inLen),
|
||||
static_cast<short*>(this->pcmData));
|
||||
aacDecoder->inputBufferCurrentLength = inLen;
|
||||
aacDecoder->inputBufferUsedLength = 0;
|
||||
aacDecoder->inputBufferMaxLength = inLen;
|
||||
aacDecoder->pInputBuffer = inData;
|
||||
aacDecoder->remainderBits = 0;
|
||||
aacDecoder->repositionFlag = true;
|
||||
|
||||
AACGetLastFrameInfo(aac, &frame);
|
||||
if (status != ERR_AAC_NONE) {
|
||||
lastErrno = status;
|
||||
int32_t status;
|
||||
status = PVMP4AudioDecodeFrame(aacDecoder, pMem);
|
||||
|
||||
if (status != MP4AUDEC_SUCCESS) {
|
||||
outLen = 0;
|
||||
inLen = 0;
|
||||
return nullptr;
|
||||
} else {
|
||||
inLen -= aacDecoder->inputBufferUsedLength;
|
||||
}
|
||||
|
||||
if (sampleRate != frame.sampRateOut) {
|
||||
this->sampleRate = frame.sampRateOut;
|
||||
outLen = aacDecoder->frameLength * sizeof(int16_t);
|
||||
|
||||
// Handle AAC+
|
||||
if (aacDecoder->aacPlusUpsamplingFactor == 2) {
|
||||
outLen *= 2;
|
||||
}
|
||||
|
||||
if (channelCount != frame.nChans) {
|
||||
this->channelCount = frame.nChans;
|
||||
}
|
||||
|
||||
outLen = frame.outputSamps * sizeof(int16_t);
|
||||
return (uint8_t*)pcmData;
|
||||
outLen *= aacDecoder->desiredChannels;
|
||||
return (uint8_t*)&outputBuffer[0];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "BaseCodec.h"
|
||||
|
||||
#include "AudioContainer.h" // for AudioContainer
|
||||
#include "CodecType.h" // for bell
|
||||
|
||||
using namespace bell;
|
||||
|
||||
@@ -23,10 +22,7 @@ uint8_t* BaseCodec::decode(AudioContainer* container, uint32_t& outLen) {
|
||||
|
||||
availableBytes = lastSampleLen;
|
||||
auto* result = decode((uint8_t*)data, availableBytes, outLen);
|
||||
if (result == nullptr) {
|
||||
container->consumeBytes(1);
|
||||
} else {
|
||||
container->consumeBytes(lastSampleLen - availableBytes);
|
||||
}
|
||||
container->consumeBytes(lastSampleLen - availableBytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "MP3Decoder.h"
|
||||
|
||||
#include <stdlib.h> // for free, malloc
|
||||
|
||||
#include "CodecType.h" // for bell
|
||||
#include <cstdio>
|
||||
|
||||
namespace bell {
|
||||
class AudioContainer;
|
||||
@@ -41,6 +40,8 @@ uint8_t* MP3Decoder::decode(uint8_t* inData, uint32_t& inLen,
|
||||
MP3GetLastFrameInfo(mp3, &frame);
|
||||
if (status != ERR_MP3_NONE) {
|
||||
lastErrno = status;
|
||||
inLen -= 2;
|
||||
outLen = 0;
|
||||
return nullptr;
|
||||
}
|
||||
if (sampleRate != frame.samprate) {
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h> // for uint8_t, uint32_t, int16_t
|
||||
#include <vector>
|
||||
|
||||
#include "BaseCodec.h" // for BaseCodec
|
||||
#include "aacdec.h" // for AACFrameInfo, HAACDecoder
|
||||
#include "BaseCodec.h" // for BaseCodec
|
||||
#include "pvmp4audiodecoder_api.h" // for tPVMP4AudioDecoderExternal
|
||||
|
||||
namespace bell {
|
||||
class AudioContainer;
|
||||
|
||||
class AACDecoder : public BaseCodec {
|
||||
private:
|
||||
HAACDecoder aac;
|
||||
int16_t* pcmData;
|
||||
AACFrameInfo frame = {};
|
||||
tPVMP4AudioDecoderExternal* aacDecoder;
|
||||
std::vector<uint8_t> inputBuffer;
|
||||
std::vector<int16_t> outputBuffer;
|
||||
void* pMem;
|
||||
bool firstFrame = true;
|
||||
|
||||
int getDecodedStreamType();
|
||||
|
||||
public:
|
||||
AACDecoder();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <stdio.h> // for NULL
|
||||
|
||||
#include "aacdec.h" // for AACFreeDecoder, AACInitDecoder, HAACDecoder
|
||||
// #include "aacdec.h" // for AACFreeDecoder, AACInitDecoder, HAACDecoder
|
||||
#include "mp3dec.h" // for MP3FreeDecoder, MP3InitDecoder, HMP3Decoder
|
||||
|
||||
namespace bell {
|
||||
@@ -16,16 +16,16 @@ class DecodersInstance {
|
||||
DecodersInstance(){};
|
||||
~DecodersInstance() {
|
||||
MP3FreeDecoder(mp3Decoder);
|
||||
AACFreeDecoder(aacDecoder);
|
||||
// AACFreeDecoder(aacDecoder);
|
||||
};
|
||||
|
||||
HAACDecoder aacDecoder = NULL;
|
||||
// HAACDecoder aacDecoder = NULL;
|
||||
HMP3Decoder mp3Decoder = NULL;
|
||||
|
||||
void ensureAAC() {
|
||||
if (aacDecoder == NULL) {
|
||||
aacDecoder = AACInitDecoder();
|
||||
}
|
||||
// if (aacDecoder == NULL) {
|
||||
// aacDecoder = AACInitDecoder();
|
||||
// }
|
||||
}
|
||||
|
||||
void ensureMP3() {
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#include "AACContainer.h"
|
||||
|
||||
#include <cstring> // for memmove
|
||||
|
||||
#include "StreamInfo.h" // for BitWidth, BitWidth::BW_16, SampleRate, Sampl...
|
||||
#include "aacdec.h" // for AACFindSyncWord
|
||||
|
||||
using namespace bell;
|
||||
|
||||
#define SYNC_WORLD_LEN 4
|
||||
|
||||
AACContainer::AACContainer(std::istream& istr) : bell::AudioContainer(istr) {}
|
||||
|
||||
bool AACContainer::fillBuffer() {
|
||||
if (this->bytesInBuffer < AAC_MAX_FRAME_SIZE * 2) {
|
||||
this->istr.read((char*)buffer.data() + bytesInBuffer,
|
||||
buffer.size() - bytesInBuffer);
|
||||
this->bytesInBuffer += istr.gcount();
|
||||
}
|
||||
return this->bytesInBuffer >= AAC_MAX_FRAME_SIZE * 2;
|
||||
}
|
||||
|
||||
std::byte* AACContainer::readSample(uint32_t& len) {
|
||||
if (!this->fillBuffer()) {
|
||||
len = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Align the data if previous read was offseted
|
||||
if (toConsume > 0 && toConsume <= bytesInBuffer) {
|
||||
memmove(buffer.data(), buffer.data() + toConsume,
|
||||
buffer.size() - toConsume);
|
||||
bytesInBuffer = bytesInBuffer - toConsume;
|
||||
toConsume = 0;
|
||||
}
|
||||
|
||||
int startOffset =
|
||||
AACFindSyncWord((uint8_t*)this->buffer.data(), bytesInBuffer);
|
||||
|
||||
if (startOffset < 0) {
|
||||
// Discard word
|
||||
toConsume = AAC_MAX_FRAME_SIZE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
len = bytesInBuffer - startOffset;
|
||||
|
||||
return this->buffer.data() + startOffset;
|
||||
}
|
||||
|
||||
void AACContainer::parseSetupData() {
|
||||
channels = 2;
|
||||
sampleRate = bell::SampleRate::SR_44100;
|
||||
bitWidth = bell::BitWidth::BW_16;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "ADTSContainer.h"
|
||||
|
||||
#include <cstring> // for memmove
|
||||
#include <iostream>
|
||||
|
||||
#include "StreamInfo.h" // for BitWidth, BitWidth::BW_16, SampleRate, Sampl...
|
||||
// #include "aacdec.h" // for AACFindSyncWord
|
||||
|
||||
using namespace bell;
|
||||
|
||||
#define SYNC_WORLD_LEN 4
|
||||
#define SYNCWORDH 0xff
|
||||
#define SYNCWORDL 0xf0
|
||||
|
||||
// AAC ADTS frame header len
|
||||
#define AAC_ADTS_FRAME_HEADER_LEN 9
|
||||
|
||||
// AAC ADTS frame sync verify
|
||||
#define AAC_ADTS_SYNC_VERIFY(buf) \
|
||||
((buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0))
|
||||
|
||||
// AAC ADTS Frame size value stores in 13 bits started at the 31th bit from header
|
||||
#define AAC_ADTS_FRAME_GETSIZE(buf) \
|
||||
((buf[3] & 0x03) << 11 | buf[4] << 3 | buf[5] >> 5)
|
||||
|
||||
ADTSContainer::ADTSContainer(std::istream& istr, const std::byte* headingBytes)
|
||||
: bell::AudioContainer(istr) {
|
||||
if (headingBytes != nullptr) {
|
||||
memcpy(buffer.data(), headingBytes, 7);
|
||||
bytesInBuffer = 7;
|
||||
}
|
||||
}
|
||||
|
||||
bool ADTSContainer::fillBuffer() {
|
||||
if (this->bytesInBuffer < AAC_MAX_FRAME_SIZE * 2) {
|
||||
this->istr.read((char*)buffer.data() + bytesInBuffer,
|
||||
buffer.size() - bytesInBuffer);
|
||||
this->bytesInBuffer += istr.gcount();
|
||||
}
|
||||
return this->bytesInBuffer >= AAC_MAX_FRAME_SIZE;
|
||||
}
|
||||
|
||||
bool ADTSContainer::resyncADTS() {
|
||||
int resyncOffset = 0;
|
||||
bool resyncValid = false;
|
||||
|
||||
size_t validBytes = bytesInBuffer - dataOffset;
|
||||
|
||||
while (!resyncValid && resyncOffset < validBytes) {
|
||||
uint8_t* buf = (uint8_t*)this->buffer.data() + dataOffset + resyncOffset;
|
||||
if (AAC_ADTS_SYNC_VERIFY(buf)) {
|
||||
// Read frame size, and check if a consecutive frame is available
|
||||
uint32_t frameSize = AAC_ADTS_FRAME_GETSIZE(buf);
|
||||
|
||||
if (frameSize + resyncOffset > validBytes) {
|
||||
// Not enough data, discard this frame
|
||||
resyncOffset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
buf =
|
||||
(uint8_t*)this->buffer.data() + dataOffset + resyncOffset + frameSize;
|
||||
|
||||
if (AAC_ADTS_SYNC_VERIFY(buf)) {
|
||||
buf += AAC_ADTS_FRAME_GETSIZE(buf);
|
||||
if (AAC_ADTS_SYNC_VERIFY(buf)) {
|
||||
protectionAbsent = (buf[1] & 1);
|
||||
|
||||
// Found 3 consecutive frames, resynced
|
||||
resyncValid = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resyncOffset++;
|
||||
}
|
||||
}
|
||||
|
||||
dataOffset += resyncOffset;
|
||||
return resyncValid;
|
||||
}
|
||||
|
||||
void ADTSContainer::consumeBytes(uint32_t len) {
|
||||
dataOffset += len;
|
||||
}
|
||||
|
||||
std::byte* ADTSContainer::readSample(uint32_t& len) {
|
||||
// Align data if previous read was offseted
|
||||
if (dataOffset > 0 && bytesInBuffer > 0) {
|
||||
size_t toConsume = std::min(dataOffset, bytesInBuffer);
|
||||
memmove(buffer.data(), buffer.data() + toConsume,
|
||||
buffer.size() - toConsume);
|
||||
|
||||
dataOffset -= toConsume;
|
||||
bytesInBuffer -= toConsume;
|
||||
}
|
||||
|
||||
if (!this->fillBuffer()) {
|
||||
len = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* buf = (uint8_t*)buffer.data() + dataOffset;
|
||||
|
||||
if (!AAC_ADTS_SYNC_VERIFY(buf)) {
|
||||
if (!resyncADTS()) {
|
||||
len = 0;
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
protectionAbsent = (buf[1] & 1);
|
||||
}
|
||||
|
||||
len = AAC_ADTS_FRAME_GETSIZE(buf);
|
||||
|
||||
if (len > bytesInBuffer - dataOffset) {
|
||||
if (!resyncADTS()) {
|
||||
len = 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.data() + dataOffset;
|
||||
}
|
||||
|
||||
void ADTSContainer::parseSetupData() {
|
||||
channels = 2;
|
||||
sampleRate = bell::SampleRate::SR_44100;
|
||||
bitWidth = bell::BitWidth::BW_16;
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "AudioContainers.h"
|
||||
|
||||
#include <string.h> // for memcmp
|
||||
#include <cstddef> // for byte
|
||||
#include <string.h> // for memcmp
|
||||
#include <cstddef> // for byte
|
||||
#include "BellLogger.h" // for BellLogger
|
||||
|
||||
#include "AACContainer.h" // for AACContainer
|
||||
#include "CodecType.h" // for bell
|
||||
#include "MP3Container.h" // for MP3Container
|
||||
#include "ADTSContainer.h" // for AACContainer
|
||||
#include "CodecType.h" // for bell
|
||||
#include "MP3Container.h" // for MP3Container
|
||||
|
||||
namespace bell {
|
||||
class AudioContainer;
|
||||
@@ -20,15 +21,19 @@ std::unique_ptr<bell::AudioContainer> AudioContainers::guessAudioContainer(
|
||||
|
||||
if (memcmp(tmp, "\xFF\xF1", 2) == 0 || memcmp(tmp, "\xFF\xF9", 2) == 0) {
|
||||
// AAC found
|
||||
std::cout << "AAC" << std::endl;
|
||||
return std::make_unique<bell::AACContainer>(istr);
|
||||
BELL_LOG(info, "AudioContainers",
|
||||
"Mime guesser found AAC in ADTS format, creating ADTSContainer");
|
||||
return std::make_unique<bell::ADTSContainer>(istr, tmp);
|
||||
} else if (memcmp(tmp, "\xFF\xFB", 2) == 0 ||
|
||||
memcmp(tmp, "\x49\x44\x33", 3) == 0) {
|
||||
// MP3 Found
|
||||
std::cout << "MP3" << std::endl;
|
||||
BELL_LOG(info, "AudioContainers",
|
||||
"Mime guesser found MP3 format, creating MP3Container");
|
||||
|
||||
return std::make_unique<bell::MP3Container>(istr);
|
||||
return std::make_unique<bell::MP3Container>(istr, tmp);
|
||||
}
|
||||
|
||||
BELL_LOG(error, "AudioContainers",
|
||||
"Mime guesser found no supported format [%X, %X]", tmp[0], tmp[1]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,12 @@
|
||||
|
||||
using namespace bell;
|
||||
|
||||
MP3Container::MP3Container(std::istream& istr) : bell::AudioContainer(istr) {}
|
||||
MP3Container::MP3Container(std::istream& istr, const std::byte* headingBytes) : bell::AudioContainer(istr) {
|
||||
if (headingBytes != nullptr) {
|
||||
memcpy(buffer.data(), headingBytes, 7);
|
||||
bytesInBuffer = 7;
|
||||
}
|
||||
}
|
||||
|
||||
bool MP3Container::fillBuffer() {
|
||||
if (this->bytesInBuffer < MP3_MAX_FRAME_SIZE * 2) {
|
||||
@@ -18,32 +23,41 @@ bool MP3Container::fillBuffer() {
|
||||
return this->bytesInBuffer >= MP3_MAX_FRAME_SIZE * 2;
|
||||
}
|
||||
|
||||
void MP3Container::consumeBytes(uint32_t len) {
|
||||
dataOffset += len;
|
||||
}
|
||||
|
||||
std::byte* MP3Container::readSample(uint32_t& len) {
|
||||
// Align data if previous read was offseted
|
||||
if (dataOffset > 0 && bytesInBuffer > 0) {
|
||||
size_t toConsume = std::min(dataOffset, bytesInBuffer);
|
||||
memmove(buffer.data(), buffer.data() + toConsume,
|
||||
buffer.size() - toConsume);
|
||||
|
||||
dataOffset -= toConsume;
|
||||
bytesInBuffer -= toConsume;
|
||||
}
|
||||
|
||||
|
||||
if (!this->fillBuffer()) {
|
||||
len = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Align the data if previous read was offseted
|
||||
if (toConsume > 0 && toConsume <= bytesInBuffer) {
|
||||
memmove(buffer.data(), buffer.data() + toConsume,
|
||||
buffer.size() - toConsume);
|
||||
bytesInBuffer = bytesInBuffer - toConsume;
|
||||
toConsume = 0;
|
||||
}
|
||||
|
||||
int startOffset =
|
||||
MP3FindSyncWord((uint8_t*)this->buffer.data(), bytesInBuffer);
|
||||
|
||||
if (startOffset < 0) {
|
||||
// Discard word
|
||||
toConsume = MP3_MAX_FRAME_SIZE;
|
||||
dataOffset = MP3_MAX_FRAME_SIZE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
len = bytesInBuffer - startOffset;
|
||||
dataOffset += startOffset;
|
||||
|
||||
return this->buffer.data() + startOffset;
|
||||
len = bytesInBuffer - dataOffset;
|
||||
|
||||
return this->buffer.data() + dataOffset;
|
||||
}
|
||||
|
||||
void MP3Container::parseSetupData() {
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
#include "CodecType.h" // for AudioCodec, AudioCodec::AAC
|
||||
|
||||
namespace bell {
|
||||
class AACContainer : public AudioContainer {
|
||||
class ADTSContainer : public AudioContainer {
|
||||
public:
|
||||
~AACContainer(){};
|
||||
AACContainer(std::istream& istr);
|
||||
~ADTSContainer(){};
|
||||
ADTSContainer(std::istream& istr, const std::byte* headingBytes = nullptr);
|
||||
|
||||
std::byte* readSample(uint32_t& len) override;
|
||||
bool resyncADTS();
|
||||
void parseSetupData() override;
|
||||
void consumeBytes(uint32_t len) override;
|
||||
|
||||
bell::AudioCodec getCodec() override { return bell::AudioCodec::AAC; }
|
||||
|
||||
@@ -27,6 +29,7 @@ class AACContainer : public AudioContainer {
|
||||
|
||||
size_t bytesInBuffer = 0;
|
||||
size_t dataOffset = 0;
|
||||
bool protectionAbsent = false;
|
||||
|
||||
bool fillBuffer();
|
||||
};
|
||||
@@ -10,7 +10,6 @@ namespace bell {
|
||||
class AudioContainer {
|
||||
protected:
|
||||
std::istream& istr;
|
||||
uint32_t toConsume = 0;
|
||||
|
||||
public:
|
||||
bell::SampleRate sampleRate;
|
||||
@@ -20,7 +19,7 @@ class AudioContainer {
|
||||
AudioContainer(std::istream& istr) : istr(istr) {}
|
||||
|
||||
virtual std::byte* readSample(uint32_t& len) = 0;
|
||||
void consumeBytes(uint32_t bytes) { this->toConsume = bytes; }
|
||||
virtual void consumeBytes(uint32_t len) = 0;
|
||||
virtual void parseSetupData() = 0;
|
||||
virtual bell::AudioCodec getCodec() = 0;
|
||||
};
|
||||
|
||||
@@ -12,10 +12,12 @@ namespace bell {
|
||||
class MP3Container : public AudioContainer {
|
||||
public:
|
||||
~MP3Container(){};
|
||||
MP3Container(std::istream& istr);
|
||||
MP3Container(std::istream& istr, const std::byte* headingBytes = nullptr);
|
||||
|
||||
std::byte* readSample(uint32_t& len) override;
|
||||
void parseSetupData() override;
|
||||
void consumeBytes(uint32_t len) override;
|
||||
|
||||
bell::AudioCodec getCodec() override { return bell::AudioCodec::MP3; }
|
||||
|
||||
private:
|
||||
@@ -26,6 +28,7 @@ class MP3Container : public AudioContainer {
|
||||
|
||||
size_t bytesInBuffer = 0;
|
||||
size_t dataOffset = 0;
|
||||
size_t toConsume = 0;
|
||||
|
||||
bool fillBuffer();
|
||||
};
|
||||
|
||||
@@ -100,7 +100,6 @@ size_t BellDSP::process(uint8_t* data, size_t bytes, int channels,
|
||||
|
||||
// Data has been downmixed to mono
|
||||
if (streamInfo->numChannels == 1) {
|
||||
|
||||
data16Bit[i] = dataLeft[i] * MAX_INT16; // Denormalize left
|
||||
} else {
|
||||
data16Bit[i * 2] = dataLeft[i] * MAX_INT16; // Denormalize left
|
||||
|
||||
@@ -49,12 +49,12 @@ ES8388AudioSink::ES8388AudioSink() {
|
||||
ESP_LOGE("OI", "i2s set pin error: %d", err);
|
||||
}
|
||||
|
||||
err = i2c_param_config(0, &i2c_config);
|
||||
err = i2c_param_config(I2C_NUM_0, &i2c_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE("OI", "i2c param config error: %d", err);
|
||||
}
|
||||
|
||||
err = i2c_driver_install(0, I2C_MODE_MASTER, 0, 0, 0);
|
||||
err = i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE("OI", "i2c driver installation error: %d", err);
|
||||
}
|
||||
@@ -132,7 +132,7 @@ void ES8388AudioSink::writeReg(uint8_t reg_add, uint8_t data) {
|
||||
res |= i2c_master_write_byte(cmd, reg_add, ACK_CHECK_EN);
|
||||
res |= i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
res |= i2c_master_stop(cmd);
|
||||
res |= i2c_master_cmd_begin(0, cmd, 1000 / portTICK_PERIOD_MS);
|
||||
res |= i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
|
||||
if (res != ESP_OK) {
|
||||
|
||||
@@ -97,7 +97,7 @@ class ES8388AudioSink : public BufferedAudioSink {
|
||||
|
||||
private:
|
||||
i2c_config_t i2c_config;
|
||||
i2c_port_t i2c_port = 0;
|
||||
i2c_port_t i2c_port = I2C_NUM_0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@ class TAS5711AudioSink : public BufferedAudioSink {
|
||||
|
||||
private:
|
||||
i2c_config_t i2c_config;
|
||||
i2c_port_t i2c_port = 0;
|
||||
i2c_port_t i2c_port = I2C_NUM_0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -35,7 +35,14 @@ class WebSocketHandler : public CivetWebSocketHandler {
|
||||
}
|
||||
|
||||
virtual bool handleData(CivetServer* server, struct mg_connection* conn,
|
||||
int bits, char* data, size_t data_len) {
|
||||
int flags, char* data, size_t data_len) {
|
||||
|
||||
if ((flags & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
|
||||
// Received close message from client. Close the connection.
|
||||
this->stateHandler(conn, BellHTTPServer::WSState::CLOSED);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->dataHandler(conn, data, data_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ using namespace bell;
|
||||
EncodedAudioStream::EncodedAudioStream() {
|
||||
bell::decodersInstance->ensureAAC();
|
||||
bell::decodersInstance->ensureMP3();
|
||||
inputBuffer = std::vector<uint8_t>(AAC_READBUF_SIZE * 4);
|
||||
outputBuffer = std::vector<short>(AAC_MAX_NCHANS * AAC_MAX_NSAMPS * 4 * 4);
|
||||
inputBuffer = std::vector<uint8_t>(1024 * 4);
|
||||
outputBuffer = std::vector<short>(2 * 2 * 4 * 4);
|
||||
decodePtr = inputBuffer.data();
|
||||
}
|
||||
|
||||
@@ -115,46 +115,47 @@ bool EncodedAudioStream::isReadable() {
|
||||
}
|
||||
|
||||
size_t EncodedAudioStream::decodeFrameAAC(uint8_t* dst) {
|
||||
size_t writtenBytes = 0;
|
||||
auto bufSize = AAC_READBUF_SIZE;
|
||||
return 0;
|
||||
// size_t writtenBytes = 0;
|
||||
// auto bufSize = AAC_READBUF_SIZE;
|
||||
|
||||
int readBytes = innerStream->read(inputBuffer.data() + bytesInBuffer,
|
||||
bufSize - bytesInBuffer);
|
||||
if (readBytes > 0) {
|
||||
bytesInBuffer += readBytes;
|
||||
decodePtr = inputBuffer.data();
|
||||
offset = AACFindSyncWord(inputBuffer.data(), bytesInBuffer);
|
||||
// int readBytes = innerStream->read(inputBuffer.data() + bytesInBuffer,
|
||||
// bufSize - bytesInBuffer);
|
||||
// if (readBytes > 0) {
|
||||
// bytesInBuffer += readBytes;
|
||||
// decodePtr = inputBuffer.data();
|
||||
// offset = AACFindSyncWord(inputBuffer.data(), bytesInBuffer);
|
||||
|
||||
if (offset != -1) {
|
||||
bytesInBuffer -= offset;
|
||||
decodePtr += offset;
|
||||
// if (offset != -1) {
|
||||
// bytesInBuffer -= offset;
|
||||
// decodePtr += offset;
|
||||
|
||||
int decodeStatus =
|
||||
AACDecode(bell::decodersInstance->aacDecoder, &decodePtr,
|
||||
&bytesInBuffer, outputBuffer.data());
|
||||
AACGetLastFrameInfo(bell::decodersInstance->aacDecoder, &aacFrameInfo);
|
||||
if (decodeStatus == ERR_AAC_NONE) {
|
||||
decodedSampleRate = aacFrameInfo.sampRateOut;
|
||||
writtenBytes =
|
||||
(aacFrameInfo.bitsPerSample / 8) * aacFrameInfo.outputSamps;
|
||||
// int decodeStatus =
|
||||
// AACDecode(bell::decodersInstance->aacDecoder, &decodePtr,
|
||||
// &bytesInBuffer, outputBuffer.data());
|
||||
// AACGetLastFrameInfo(bell::decodersInstance->aacDecoder, &aacFrameInfo);
|
||||
// if (decodeStatus == ERR_AAC_NONE) {
|
||||
// decodedSampleRate = aacFrameInfo.sampRateOut;
|
||||
// writtenBytes =
|
||||
// (aacFrameInfo.bitsPerSample / 8) * aacFrameInfo.outputSamps;
|
||||
|
||||
memcpy(dst, outputBuffer.data(), writtenBytes);
|
||||
// memcpy(dst, outputBuffer.data(), writtenBytes);
|
||||
|
||||
} else {
|
||||
BELL_LOG(info, TAG, "Error in frame, moving two bytes %d",
|
||||
decodeStatus);
|
||||
decodePtr += 1;
|
||||
bytesInBuffer -= 1;
|
||||
}
|
||||
} else {
|
||||
BELL_LOG(info, TAG, "Unexpected error in data, skipping a word");
|
||||
decodePtr += 3800;
|
||||
bytesInBuffer -= 3800;
|
||||
}
|
||||
// } else {
|
||||
// BELL_LOG(info, TAG, "Error in frame, moving two bytes %d",
|
||||
// decodeStatus);
|
||||
// decodePtr += 1;
|
||||
// bytesInBuffer -= 1;
|
||||
// }
|
||||
// } else {
|
||||
// BELL_LOG(info, TAG, "Unexpected error in data, skipping a word");
|
||||
// decodePtr += 3800;
|
||||
// bytesInBuffer -= 3800;
|
||||
// }
|
||||
|
||||
memmove(inputBuffer.data(), decodePtr, bytesInBuffer);
|
||||
}
|
||||
return writtenBytes;
|
||||
// memmove(inputBuffer.data(), decodePtr, bytesInBuffer);
|
||||
// }
|
||||
// return writtenBytes;
|
||||
}
|
||||
|
||||
void EncodedAudioStream::guessDataFormat() {
|
||||
|
||||
77
components/spotify/cspot/bell/main/io/MGStreamAdapter.cpp
Normal file
77
components/spotify/cspot/bell/main/io/MGStreamAdapter.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
// MGStreamAdapter.cpp
|
||||
#include "MGStreamAdapter.h"
|
||||
|
||||
mg_buf::mg_buf(struct mg_connection* _conn) : conn(_conn) {
|
||||
setp(buffer, buffer + BUF_SIZE - 1); // -1 to leave space for overflow '\0'
|
||||
}
|
||||
|
||||
mg_buf::int_type mg_buf::overflow(int_type c) {
|
||||
if (c != EOF) {
|
||||
*pptr() = c;
|
||||
pbump(1);
|
||||
}
|
||||
|
||||
if (flush_buffer() == EOF) {
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int mg_buf::flush_buffer() {
|
||||
int len = int(pptr() - pbase());
|
||||
if (mg_write(conn, buffer, len) != len) {
|
||||
return EOF;
|
||||
}
|
||||
pbump(-len); // reset put pointer accordingly
|
||||
return len;
|
||||
}
|
||||
|
||||
int mg_buf::sync() {
|
||||
if (flush_buffer() == EOF) {
|
||||
return -1; // return -1 on error
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MGStreamAdapter::MGStreamAdapter(struct mg_connection* _conn) : std::ostream(&buf), buf(_conn) {
|
||||
rdbuf(&buf); // set the custom streambuf
|
||||
}
|
||||
|
||||
|
||||
mg_read_buf::mg_read_buf(struct mg_connection* _conn) : conn(_conn) {
|
||||
setg(buffer + BUF_SIZE, // beginning of putback area
|
||||
buffer + BUF_SIZE, // read position
|
||||
buffer + BUF_SIZE); // end position
|
||||
}
|
||||
|
||||
mg_read_buf::int_type mg_read_buf::underflow() {
|
||||
if (gptr() < egptr()) { // buffer not exhausted
|
||||
return traits_type::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
char* base = buffer;
|
||||
char* start = base;
|
||||
|
||||
if (eback() == base) { // true when this isn't the first fill
|
||||
// Make arrangements for putback characters
|
||||
std::memmove(base, egptr() - 2, 2);
|
||||
start += 2;
|
||||
}
|
||||
|
||||
// Read new characters
|
||||
int n = mg_read(conn, start, buffer + BUF_SIZE - start);
|
||||
if (n == 0) {
|
||||
return traits_type::eof();
|
||||
}
|
||||
|
||||
// Set buffer pointers
|
||||
setg(base, start, start + n);
|
||||
|
||||
// Return next character
|
||||
return traits_type::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
MGInputStreamAdapter::MGInputStreamAdapter(struct mg_connection* _conn) : std::istream(&buf), buf(_conn) {
|
||||
rdbuf(&buf); // set the custom streambuf
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class reader {
|
||||
reader(std::istream& inp)
|
||||
: _inp(inp), _cached_header_data_valid(false), _number_of_files(-1) {}
|
||||
|
||||
// Returns true iff another file can be read from |inp|.
|
||||
// Returns true if another file can be read from |inp|.
|
||||
bool contains_another_file();
|
||||
|
||||
// Returns file name of next file in |inp|.
|
||||
@@ -72,4 +72,4 @@ class reader {
|
||||
// Returns number of files in tar at |inp|.
|
||||
int number_of_files();
|
||||
};
|
||||
} // namespace bell::BellTar
|
||||
} // namespace bell::BellTar
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
#if __has_include(<bit>)
|
||||
#include <bit> // for endian
|
||||
#endif
|
||||
|
||||
#include <stdint.h> // for int16_t, int32_t, int64_t, uint16_t, uint32_t
|
||||
#include <cstddef> // for byte
|
||||
#include <iostream> // for istream, ostream
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <string> // for basic_string, string
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "aacdec.h" // for AACFrameInfo
|
||||
#include "mp3dec.h" // for MP3FrameInfo
|
||||
|
||||
namespace bell {
|
||||
@@ -48,7 +47,7 @@ class EncodedAudioStream {
|
||||
std::vector<uint8_t> mp3MagicBytesUntagged = {0xFF, 0xFB};
|
||||
std::vector<uint8_t> mp3MagicBytesIdc = {0x49, 0x44, 0x33};
|
||||
|
||||
AACFrameInfo aacFrameInfo;
|
||||
// AACFrameInfo aacFrameInfo;
|
||||
MP3FrameInfo mp3FrameInfo;
|
||||
|
||||
size_t decodeFrameMp3(uint8_t* dst);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <cstring>
|
||||
#include "civetweb.h"
|
||||
|
||||
const size_t BUF_SIZE = 1024;
|
||||
|
||||
// Custom streambuf
|
||||
class mg_buf : public std::streambuf {
|
||||
private:
|
||||
struct mg_connection* conn;
|
||||
char buffer[BUF_SIZE];
|
||||
|
||||
public:
|
||||
mg_buf(struct mg_connection* _conn);
|
||||
|
||||
protected:
|
||||
virtual int_type overflow(int_type c);
|
||||
int flush_buffer();
|
||||
virtual int sync();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adapts ostream to mg_write
|
||||
*
|
||||
*/
|
||||
class MGStreamAdapter : public std::ostream {
|
||||
private:
|
||||
mg_buf buf;
|
||||
|
||||
public:
|
||||
MGStreamAdapter(struct mg_connection* _conn);
|
||||
};
|
||||
|
||||
// Custom streambuf
|
||||
class mg_read_buf : public std::streambuf {
|
||||
private:
|
||||
struct mg_connection* conn;
|
||||
char buffer[BUF_SIZE];
|
||||
|
||||
public:
|
||||
mg_read_buf(struct mg_connection* _conn);
|
||||
|
||||
protected:
|
||||
virtual int_type underflow();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adapts istream to mg_read
|
||||
*/
|
||||
class MGInputStreamAdapter : public std::istream {
|
||||
private:
|
||||
mg_read_buf buf;
|
||||
|
||||
public:
|
||||
MGInputStreamAdapter(struct mg_connection* _conn);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <random> // for mt19937, uniform_int_distribution, random_device
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_system.h"
|
||||
#if __has_include("esp_mac.h")
|
||||
#include "esp_mac.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::string bell::generateRandomUUID() {
|
||||
@@ -27,6 +30,7 @@ std::string bell::generateRandomUUID() {
|
||||
|
||||
std::string bell::getMacAddress() {
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
uint8_t mac[6];
|
||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||
char macStr[18];
|
||||
|
||||
@@ -135,14 +135,20 @@ std::vector<uint8_t> CryptoMbedTLS::pbkdf2HmacSha1(
|
||||
int iterations, int digestSize) {
|
||||
auto digest = std::vector<uint8_t>(digestSize);
|
||||
|
||||
#if MBEDTLS_VERSION_NUMBER < 0x03030000
|
||||
// Init sha context
|
||||
sha1Init();
|
||||
mbedtls_pkcs5_pbkdf2_hmac(&sha1Context, password.data(), password.size(),
|
||||
salt.data(), salt.size(), iterations, digestSize,
|
||||
digest.data());
|
||||
|
||||
|
||||
// Free sha context
|
||||
mbedtls_md_free(&sha1Context);
|
||||
#else
|
||||
mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, password.data(), password.size(),
|
||||
salt.data(), salt.size(), iterations, digestSize,
|
||||
digest.data());
|
||||
#endif
|
||||
|
||||
return digest;
|
||||
}
|
||||
@@ -230,4 +236,4 @@ std::vector<uint8_t> CryptoMbedTLS::generateVectorWithRandomData(
|
||||
mbedtls_ctr_drbg_free(&ctrDrbg);
|
||||
|
||||
return randomVector;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user