mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-01-02 22:59:14 +03:00
update cspot
This commit is contained in:
37
components/spotify/cspot/bell/src/audio/codec/AACDecoder.cpp
Normal file
37
components/spotify/cspot/bell/src/audio/codec/AACDecoder.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
|
||||
|
||||
#include "AACDecoder.h"
|
||||
|
||||
AACDecoder::AACDecoder() {
|
||||
aac = AACInitDecoder();
|
||||
pcmData = (int16_t *)malloc(AAC_MAX_NSAMPS * AAC_MAX_NCHANS * sizeof(int16_t));
|
||||
}
|
||||
|
||||
AACDecoder::~AACDecoder() {
|
||||
AACFreeDecoder(aac);
|
||||
free(pcmData);
|
||||
}
|
||||
|
||||
bool AACDecoder::setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
frame.sampRateCore = (int)sampleRate;
|
||||
frame.nChans = channelCount;
|
||||
frame.bitsPerSample = bitDepth;
|
||||
return AACSetRawBlockParams(aac, 0, &frame) == 0;
|
||||
}
|
||||
|
||||
uint8_t *AACDecoder::decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) {
|
||||
if (!inData)
|
||||
return nullptr;
|
||||
int status = AACDecode(
|
||||
aac,
|
||||
static_cast<unsigned char **>(&inData),
|
||||
reinterpret_cast<int *>(&inLen),
|
||||
static_cast<short *>(this->pcmData));
|
||||
AACGetLastFrameInfo(aac, &frame);
|
||||
if (status != ERR_AAC_NONE) {
|
||||
lastErrno = status;
|
||||
return nullptr;
|
||||
}
|
||||
outLen = frame.outputSamps * sizeof(int16_t);
|
||||
return (uint8_t *)pcmData;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
|
||||
|
||||
#include "ALACDecoder.h"
|
||||
|
||||
ALACDecoder::ALACDecoder() {
|
||||
// aac = AACInitDecoder();
|
||||
// pcmData = (int16_t *)malloc(AAC_MAX_NSAMPS * AAC_MAX_NCHANS * sizeof(int16_t));
|
||||
}
|
||||
|
||||
ALACDecoder::~ALACDecoder() {
|
||||
// AACFreeDecoder(aac);
|
||||
// free(pcmData);
|
||||
}
|
||||
|
||||
bool ALACDecoder::setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
// frame.sampRateCore = (int)sampleRate;
|
||||
// frame.nChans = channelCount;
|
||||
// frame.bitsPerSample = bitDepth;
|
||||
// return AACSetRawBlockParams(aac, 0, &frame) == 0;
|
||||
}
|
||||
|
||||
uint8_t *ALACDecoder::decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) {
|
||||
// if (!inData)
|
||||
// return nullptr;
|
||||
// int status = AACDecode(
|
||||
// aac,
|
||||
// static_cast<unsigned char **>(&inData),
|
||||
// reinterpret_cast<int *>(&inLen),
|
||||
// static_cast<short *>(this->pcmData));
|
||||
// AACGetLastFrameInfo(aac, &frame);
|
||||
// if (status != ERR_AAC_NONE) {
|
||||
// lastErrno = status;
|
||||
// return nullptr;
|
||||
// }
|
||||
// outLen = frame.outputSamps * sizeof(int16_t);
|
||||
// return (uint8_t *)pcmData;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
|
||||
|
||||
#include "AudioCodecs.h"
|
||||
#include <map>
|
||||
|
||||
#ifdef BELL_CODEC_AAC
|
||||
#include "AACDecoder.h"
|
||||
static std::shared_ptr<AACDecoder> codecAac;
|
||||
#endif
|
||||
|
||||
#ifdef BELL_CODEC_MP3
|
||||
#include "MP3Decoder.h"
|
||||
static std::shared_ptr<MP3Decoder> codecMp3;
|
||||
#endif
|
||||
|
||||
#ifdef BELL_CODEC_VORBIS
|
||||
#include "VorbisDecoder.h"
|
||||
static std::shared_ptr<VorbisDecoder> codecVorbis;
|
||||
#endif
|
||||
|
||||
#ifdef BELL_CODEC_OPUS
|
||||
#include "OPUSDecoder.h"
|
||||
static std::shared_ptr<OPUSDecoder> codecOpus;
|
||||
#endif
|
||||
|
||||
std::map<AudioCodec, std::shared_ptr<BaseCodec>> customCodecs;
|
||||
|
||||
std::shared_ptr<BaseCodec> AudioCodecs::getCodec(AudioCodec type) {
|
||||
if (customCodecs.find(type) != customCodecs.end())
|
||||
return customCodecs[type];
|
||||
switch (type) {
|
||||
#ifdef BELL_CODEC_AAC
|
||||
case AudioCodec::AAC:
|
||||
if (codecAac)
|
||||
return codecAac;
|
||||
codecAac = std::make_shared<AACDecoder>();
|
||||
return codecAac;
|
||||
#endif
|
||||
#ifdef BELL_CODEC_MP3
|
||||
case AudioCodec::MP3:
|
||||
if (codecMp3)
|
||||
return codecMp3;
|
||||
codecMp3 = std::make_shared<MP3Decoder>();
|
||||
return codecMp3;
|
||||
#endif
|
||||
#ifdef BELL_CODEC_VORBIS
|
||||
case AudioCodec::VORBIS:
|
||||
if (codecVorbis)
|
||||
return codecVorbis;
|
||||
codecVorbis = std::make_shared<VorbisDecoder>();
|
||||
return codecVorbis;
|
||||
#endif
|
||||
#ifdef BELL_CODEC_OPUS
|
||||
case AudioCodec::OPUS:
|
||||
if (codecOpus)
|
||||
return codecOpus;
|
||||
codecOpus = std::make_shared<OPUSDecoder>();
|
||||
return codecOpus;
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseCodec> AudioCodecs::getCodec(BaseContainer *container) {
|
||||
return getCodec(container->codec);
|
||||
}
|
||||
|
||||
void AudioCodecs::addCodec(AudioCodec type, const std::shared_ptr<BaseCodec> &codec) {
|
||||
customCodecs[type] = codec;
|
||||
}
|
||||
13
components/spotify/cspot/bell/src/audio/codec/BaseCodec.cpp
Normal file
13
components/spotify/cspot/bell/src/audio/codec/BaseCodec.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Kuba Szczodrzyński 2022-1-12.
|
||||
|
||||
#include "BaseCodec.h"
|
||||
|
||||
bool BaseCodec::setup(BaseContainer *container) {
|
||||
return this->setup(container->sampleRate, container->channelCount, container->bitDepth);
|
||||
}
|
||||
|
||||
uint8_t *BaseCodec::decode(BaseContainer *container, uint32_t &outLen) {
|
||||
uint32_t len;
|
||||
auto *data = container->readSample(len);
|
||||
return decode(data, len, outLen);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "DecoderGlobals.h"
|
||||
|
||||
bell::DecodersInstance* bell::decodersInstance;
|
||||
|
||||
void bell::createDecoders()
|
||||
{
|
||||
bell::decodersInstance = new bell::DecodersInstance();
|
||||
}
|
||||
35
components/spotify/cspot/bell/src/audio/codec/MP3Decoder.cpp
Normal file
35
components/spotify/cspot/bell/src/audio/codec/MP3Decoder.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
|
||||
|
||||
#include "MP3Decoder.h"
|
||||
|
||||
MP3Decoder::MP3Decoder() {
|
||||
mp3 = MP3InitDecoder();
|
||||
pcmData = (int16_t *)malloc(MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t));
|
||||
}
|
||||
|
||||
MP3Decoder::~MP3Decoder() {
|
||||
MP3FreeDecoder(mp3);
|
||||
free(pcmData);
|
||||
}
|
||||
|
||||
bool MP3Decoder::setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *MP3Decoder::decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) {
|
||||
if (!inData)
|
||||
return nullptr;
|
||||
int status = MP3Decode(
|
||||
mp3,
|
||||
static_cast<unsigned char **>(&inData),
|
||||
reinterpret_cast<int *>(&inLen),
|
||||
static_cast<short *>(this->pcmData),
|
||||
/* useSize */ 0);
|
||||
MP3GetLastFrameInfo(mp3, &frame);
|
||||
if (status != ERR_MP3_NONE) {
|
||||
lastErrno = status;
|
||||
return nullptr;
|
||||
}
|
||||
outLen = frame.outputSamps * sizeof(int16_t);
|
||||
return (uint8_t *)pcmData;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
|
||||
|
||||
#include "OPUSDecoder.h"
|
||||
#include "opus.h"
|
||||
|
||||
#define MAX_FRAME_SIZE 6 * 960
|
||||
#define MAX_CHANNELS 2
|
||||
|
||||
// dummy structure, just to get access to channels
|
||||
struct OpusDecoder {
|
||||
int dummy1;
|
||||
int dummy2;
|
||||
int channels;
|
||||
};
|
||||
|
||||
OPUSDecoder::OPUSDecoder() {
|
||||
opus = nullptr;
|
||||
pcmData = (int16_t *)malloc(MAX_FRAME_SIZE * MAX_CHANNELS * sizeof(int16_t));
|
||||
}
|
||||
|
||||
OPUSDecoder::~OPUSDecoder() {
|
||||
if (opus)
|
||||
opus_decoder_destroy(opus);
|
||||
free(pcmData);
|
||||
}
|
||||
|
||||
bool OPUSDecoder::setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
if (opus)
|
||||
opus_decoder_destroy(opus);
|
||||
opus = opus_decoder_create((int32_t)sampleRate, channelCount, &lastErrno);
|
||||
return !lastErrno;
|
||||
}
|
||||
|
||||
uint8_t *OPUSDecoder::decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) {
|
||||
if (!inData)
|
||||
return nullptr;
|
||||
outLen = opus_decode(
|
||||
opus,
|
||||
static_cast<unsigned char *>(inData),
|
||||
static_cast<int32_t>(inLen),
|
||||
pcmData,
|
||||
MAX_FRAME_SIZE,
|
||||
false);
|
||||
outLen *= opus->channels * sizeof(int16_t);
|
||||
return (uint8_t *)pcmData;
|
||||
}
|
||||
120
components/spotify/cspot/bell/src/audio/codec/VorbisDecoder.cpp
Normal file
120
components/spotify/cspot/bell/src/audio/codec/VorbisDecoder.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) Kuba Szczodrzyński 2022-1-14.
|
||||
|
||||
#include "VorbisDecoder.h"
|
||||
#include "AudioCodecs.h"
|
||||
|
||||
extern "C" {
|
||||
extern vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi);
|
||||
extern void vorbis_dsp_destroy(vorbis_dsp_state *v);
|
||||
extern int vorbis_dsp_restart(vorbis_dsp_state *v);
|
||||
extern int vorbis_dsp_headerin(vorbis_info *vi, vorbis_comment *vc, ogg_packet *op);
|
||||
extern int vorbis_dsp_synthesis(vorbis_dsp_state *vd, ogg_packet *op, int decodep);
|
||||
extern int vorbis_dsp_pcmout(vorbis_dsp_state *v, ogg_int16_t *pcm, int samples);
|
||||
extern int vorbis_dsp_read(vorbis_dsp_state *v, int samples);
|
||||
}
|
||||
|
||||
#define VORBIS_BUF_SAMPLES 1024
|
||||
#define VORBIS_BUF_CHANNELS 2
|
||||
|
||||
VorbisDecoder::VorbisDecoder() {
|
||||
vi = new vorbis_info;
|
||||
vorbis_info_init(vi);
|
||||
vc = new vorbis_comment;
|
||||
vorbis_comment_init(vc);
|
||||
|
||||
op.packet = new ogg_reference;
|
||||
op.packet->buffer = new ogg_buffer;
|
||||
op.packet->buffer->refcount = 0;
|
||||
op.packet->buffer->ptr.owner = nullptr;
|
||||
op.packet->buffer->ptr.next = nullptr;
|
||||
op.packet->begin = 0;
|
||||
op.packet->next = nullptr;
|
||||
op.granulepos = -1;
|
||||
op.packetno = 10;
|
||||
|
||||
pcmData = (int16_t *)malloc(VORBIS_BUF_SAMPLES * VORBIS_BUF_CHANNELS * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
VorbisDecoder::~VorbisDecoder() {
|
||||
vorbis_info_clear(vi);
|
||||
vorbis_comment_clear(vc);
|
||||
if (vd)
|
||||
vorbis_dsp_destroy(vd);
|
||||
vd = nullptr;
|
||||
free(pcmData);
|
||||
}
|
||||
|
||||
bool VorbisDecoder::setup(BaseContainer *container) {
|
||||
uint32_t setupLen;
|
||||
uint8_t *setup = container->getSetupData(setupLen, AudioCodec::VORBIS);
|
||||
if (!setup)
|
||||
return false;
|
||||
op.b_o_s = true; // mark this page as beginning of stream
|
||||
uint32_t bytesLeft = setupLen - 1; // minus header count length (8 bit)
|
||||
std::vector<uint32_t> headers(setup[0]);
|
||||
for (uint8_t i = 0; i < setup[0]; i++) {
|
||||
uint8_t *sizeByte = (uint8_t *)setup + 1 + i;
|
||||
headers[i] = 0;
|
||||
while (*sizeByte == 255) {
|
||||
headers[i] += *(sizeByte++);
|
||||
bytesLeft--;
|
||||
}
|
||||
headers[i] += *sizeByte;
|
||||
bytesLeft--;
|
||||
}
|
||||
// parse all headers from the setup data
|
||||
for (const auto &headerSize : headers) {
|
||||
setPacket(setup + setupLen - bytesLeft, headerSize);
|
||||
bytesLeft -= headerSize;
|
||||
lastErrno = vorbis_dsp_headerin(vi, vc, &op);
|
||||
if (lastErrno < 0) {
|
||||
bytesLeft = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// parse last header, not present in header table (seems to happen for MP4 containers)
|
||||
if (bytesLeft) {
|
||||
setPacket(setup + setupLen - bytesLeft, bytesLeft);
|
||||
lastErrno = vorbis_dsp_headerin(vi, vc, &op);
|
||||
}
|
||||
// disable BOS to allow reading audio data
|
||||
op.b_o_s = false;
|
||||
// set up the codec
|
||||
if (vd)
|
||||
vorbis_dsp_restart(vd);
|
||||
else
|
||||
vd = vorbis_dsp_create(vi);
|
||||
return !lastErrno;
|
||||
}
|
||||
|
||||
bool VorbisDecoder::setup(uint32_t sampleRate, uint8_t channelCount, uint8_t bitDepth) {
|
||||
// manual setup is not allowed
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *VorbisDecoder::decode(uint8_t *inData, uint32_t inLen, uint32_t &outLen) {
|
||||
if (!inData || !vi)
|
||||
return nullptr;
|
||||
setPacket(inData, inLen);
|
||||
// sources:
|
||||
// - vorbisfile.c:556
|
||||
// - vorbisfile.c:1557
|
||||
lastErrno = vorbis_dsp_synthesis(vd, &op, 1);
|
||||
if (lastErrno < 0)
|
||||
return nullptr;
|
||||
int samples = vorbis_dsp_pcmout(vd, pcmData, VORBIS_BUF_SAMPLES);
|
||||
outLen = samples;
|
||||
if (samples) {
|
||||
if (samples > 0) {
|
||||
vorbis_dsp_read(vd, samples);
|
||||
outLen = samples * 2 * vi->channels;
|
||||
}
|
||||
}
|
||||
return (uint8_t *)pcmData;
|
||||
}
|
||||
|
||||
void VorbisDecoder::setPacket(uint8_t *inData, uint32_t inLen) const {
|
||||
op.packet->buffer->data = static_cast<unsigned char *>(inData);
|
||||
op.packet->buffer->size = static_cast<long>(inLen);
|
||||
op.packet->length = static_cast<long>(inLen);
|
||||
}
|
||||
Reference in New Issue
Block a user