From 3aec88e87d5e627a4ce2e0c17a68b657c8348396 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Fri, 24 May 2019 22:09:27 -0700 Subject: [PATCH] adding vorbis and alac --- components/codecs/component.mk | 3 +- components/codecs/inc/alac/alac_wrapper.h | 40 ++ .../vorbis/{vorbisfile.h => ivorbisfile.h} | 0 components/codecs/lib/libalac.a | Bin 0 -> 169116 bytes main/alac.c | 538 ++++++++++++++++++ main/component.mk | 6 +- main/decode.c | 4 +- main/squeezelite.h | 1 + main/vorbis.c | 13 +- 9 files changed, 597 insertions(+), 8 deletions(-) create mode 100644 components/codecs/inc/alac/alac_wrapper.h rename components/codecs/inc/vorbis/{vorbisfile.h => ivorbisfile.h} (100%) create mode 100644 components/codecs/lib/libalac.a create mode 100644 main/alac.c diff --git a/components/codecs/component.mk b/components/codecs/component.mk index b5966e79..b08ea173 100644 --- a/components/codecs/component.mk +++ b/components/codecs/component.mk @@ -7,7 +7,8 @@ COMPONENT_ADD_LDFLAGS=-l$(COMPONENT_NAME) \ $(COMPONENT_PATH)/lib/libesp-flac.a \ $(COMPONENT_PATH)/lib/libfaad.a \ $(COMPONENT_PATH)/lib/libvorbisidec.a \ - $(COMPONENT_PATH)/lib/libogg.a + $(COMPONENT_PATH)/lib/libogg.a \ + $(COMPONENT_PATH)/lib/libalac.a #$(COMPONENT_PATH)/lib/libvorbisidec.a #$(COMPONENT_PATH)/lib/libogg.a diff --git a/components/codecs/inc/alac/alac_wrapper.h b/components/codecs/inc/alac/alac_wrapper.h new file mode 100644 index 00000000..5f014839 --- /dev/null +++ b/components/codecs/inc/alac/alac_wrapper.h @@ -0,0 +1,40 @@ +/***************************************************************************** + * alac_wrapper.h: ALAC coder wrapper + * + * Copyright (C) 2016 Philippe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ +#ifndef __ALAC_WRAPPER_H_ +#define __ALAC_WRAPPER_H_ + +struct alac_codec_s; + +#ifdef __cplusplus +extern "C" { +#endif + +struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie, + unsigned char *sample_size, unsigned *sample_rate, + unsigned char *channels); +void alac_delete_decoder(struct alac_codec_s *codec); +bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input, + unsigned char *output, char channels, unsigned *out_frames); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/components/codecs/inc/vorbis/vorbisfile.h b/components/codecs/inc/vorbis/ivorbisfile.h similarity index 100% rename from components/codecs/inc/vorbis/vorbisfile.h rename to components/codecs/inc/vorbis/ivorbisfile.h diff --git a/components/codecs/lib/libalac.a b/components/codecs/lib/libalac.a new file mode 100644 index 0000000000000000000000000000000000000000..48d4a8596d3f1c83bed698dbc15a05820fda7896 GIT binary patch literal 169116 zcmeFa34E2s+4n#9*>aK`AR+7oI42}*0wy6qSPfxUR17@RB`KwH zmGT{pyW)vT{a4*j3zYg#oHMIfIe&WbzwA88Vf8QFf+5P|y7H2WspS>X1;x>_;;GSD zQ%j>|(fQ?y;&`Zd*@CIXB{LSzFI9zeDhe0PoLN#fa>1O6c&Ml(T3kOgW`1c&FOVT#lk{^g%u00(AXnaU`(M`p1_#Guz3rk z6(WHN$5eH=S6+R6VJfGW&N4U8B--@Osu@7SRkE@t74}HC)y!*n7lZGxRo)cX#dSO{bbo#s!N-#h% zDnTY;Y!2&Le-6vZ&hFI<^IC3RUbZ`{O-oumbks1%aWIv+o1?B(@sLurlOgvim8YXS zskW-MI(vx@RGvMn)EPK#y#}e!?wZCmp03q38KF;Va&J_s&-9wYs+}ilimGbQjx4LG zYIDlfYoVGJsOp`YcBwv%`*`wiOs+22RyQ(ZQf^J*wxT)HmzDL=s;bvcwQOUb8$-dZ zHy+s-YCa&iq4%1)Th>(e2+xUB=g!X9S~w@QCTH8u@ngEqPbiqNdHh=!9l0_8#v@&~ zMpk@N-Q$%1I(2s9!N`%w)<})hHJIHy`@keR}0;kxQ@S)%7iq_#G*a!KmmXS#+;tHVz|6xo#MQ>_Zr?wwt$_aCfN$psts zZ`^vlN-U_Y+=ygrJ?h}~wGY;*q=L%IjYkG;z3O1JZfVMfTQ)!S?%IZGYfkHTYxm6f z-H8sZy0>1cnir^}JG&-_n%CY_N2^PACNF`hy1I>f-z}}K`de3j^1CRnO0Isj`qs0j zYJIh}(^~HcHQ%stQ0ek;>9(pzmD=WOopITaTb}kD?yrudR_#1nx2o#YcU7g!29>U= zTmI$ARjEr3de-(<6LLL)Udpy@!jd2Pbd&yYgQ7Jn53)^w~nhZ5WCeT7TC=N&At}leMef znOt30ozi;QhU%)WAy)o|ooJ3{*ovk5QRU>NcfY&*hQD3pO@4P}aQUXYdiL6$aGNib z)Gc9gm3L3@vg(52wcQeLL}u-l9CSjBLJb2R^?7or(J+V_O*r5gHveqMvsS5$M_$i= zw0dLqyLG!F!DG*c-wq}lLv zOM*Xx#N+V~X2_FpC6amjGQQ;mNPIs3oCOuin?XsdIn?nbbcBv4=-?M2S8Y-=EhLlB7c@83J?QrTB-J zK@^y=s7(1s5>=oCrxE^3$-ac&;Mac{jRq55C66M9V09IIFHQKbpwUDhTP)Cb4>;{V*nLuLX*|nYc!5brvQMyZBdOh})WTc~GcA-GXu$pKs;dwOfiqXvvJJ$I zmYPsQU4r>K*R&`z9f%*rG3IQ)3z|)I?gN>-Q`BS^&FHS0paSoN=zn@ookanlm>K4p^Zlq3OJ%t2qhXMem?@^bWd<6?jJr(TG~55!y~egVV8O z4KF6X$4aFvR?ho`hUv`nq(PZ$R#bMTC;q?CAz9vzr z)_Mn~INXEn5Yzfo{6Ld&1;F%D^lv0Y@HzzBjCZ4H$Qjpq2`l89T?a{PPRt0i9uETB zas)JX*urlj*lqw@IZYe;gkfFlCJxKkmiez_yc_;K!|%kyUjo}=%r({8jZmGo*imk% zJwjo$mK$n|JY6cH7K-nNZlKouGO5*Z0Yc8itYz>%gfQzSKt=$-mYDrO@}NFy_*4g%it{e67UF| zljG#Te#;I`B!+W5EDct)}|tuFd2%ER(b#ZS9jn(3>% zzz`_3%V&oDbQhS;1YMcI5IClAMmu-FZ_jFUvO=B9KIrNy)ahI@rlJ8xLF*(_jd89= zo!j3AS^Jyt({dSpegnmp3ju!tWKu8dPK3_T&`!WOjLWQt05yas0nZWY0LKA(-&}

qr8)q>57eOge2TI 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 literal 0 HcmV?d00001 diff --git a/main/alac.c b/main/alac.c new file mode 100644 index 00000000..36e98c48 --- /dev/null +++ b/main/alac.c @@ -0,0 +1,538 @@ +/* + * Squeezelite - lightweight headless squeezebox emulator + * + * (c) Adrian Smith 2012-2015, triode1@btinternet.com + * (c) Philippe, philippe_44@outlook.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "squeezelite.h" + +#include + +#define BLOCK_SIZE (4096 * BYTES_PER_FRAME) +#define MIN_READ BLOCK_SIZE +#define MIN_SPACE (MIN_READ * 4) + +struct chunk_table { + u32_t sample, offset; +}; + +struct alac { + void *decoder; + u8_t *writebuf; + // following used for mp4 only + u32_t consume; + u32_t pos; + u32_t sample; + u32_t nextchunk; + void *stsc; + u32_t skip; + u64_t samples; + u64_t sttssamples; + bool empty; + struct chunk_table *chunkinfo; + u32_t *block_size, default_block_size, block_index; + unsigned sample_rate; + unsigned char channels, sample_size; + unsigned trak, play; +}; + +static struct alac *l; + +extern log_level loglevel; + +extern struct buffer *streambuf; +extern struct buffer *outputbuf; +extern struct streamstate stream; +extern struct outputstate output; +extern struct decodestate decode; +extern struct processstate process; + +#define LOCK_S mutex_lock(streambuf->mutex) +#define UNLOCK_S mutex_unlock(streambuf->mutex) +#define LOCK_O mutex_lock(outputbuf->mutex) +#define UNLOCK_O mutex_unlock(outputbuf->mutex) +#if PROCESS +#define LOCK_O_direct if (decode.direct) mutex_lock(outputbuf->mutex) +#define UNLOCK_O_direct if (decode.direct) mutex_unlock(outputbuf->mutex) +#define LOCK_O_not_direct if (!decode.direct) mutex_lock(outputbuf->mutex) +#define UNLOCK_O_not_direct if (!decode.direct) mutex_unlock(outputbuf->mutex) +#define IF_DIRECT(x) if (decode.direct) { x } +#define IF_PROCESS(x) if (!decode.direct) { x } +#else +#define LOCK_O_direct mutex_lock(outputbuf->mutex) +#define UNLOCK_O_direct mutex_unlock(outputbuf->mutex) +#define LOCK_O_not_direct +#define UNLOCK_O_not_direct +#define IF_DIRECT(x) { x } +#define IF_PROCESS(x) +#endif + +// read mp4 header to extract config data +static int read_mp4_header(void) { + size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); + char type[5]; + u32_t len; + + while (bytes >= 8) { + // count trak to find the first playable one + u32_t consume; + + len = unpackN((u32_t *)streambuf->readp); + memcpy(type, streambuf->readp + 4, 4); + type[4] = '\0'; + + if (!strcmp(type, "moov")) { + l->trak = 0; + l->play = 0; + } + if (!strcmp(type, "trak")) { + l->trak++; + } + + // extract audio config from within alac + if (!strcmp(type, "alac") && bytes > len) { + u8_t *ptr = streambuf->readp + 36; + l->decoder = alac_create_decoder(len - 36, ptr, &l->sample_size, &l->sample_rate, &l->channels); + l->play = l->trak; + } + + // extract the total number of samples from stts + if (!strcmp(type, "stsz") && bytes > len) { + u32_t i; + u8_t *ptr = streambuf->readp + 12; + l->default_block_size = unpackN((u32_t *) ptr); ptr += 4; + if (!l->default_block_size) { + u32_t entries = unpackN((u32_t *)ptr); ptr += 4; + l->block_size = malloc((entries + 1)* 4); + for (i = 0; i < entries; i++) { + l->block_size[i] = unpackN((u32_t *)ptr); ptr += 4; + } + l->block_size[entries] = 0; + LOG_DEBUG("total blocksize contained in stsz %u", entries); + } else { + LOG_DEBUG("fixed blocksize in stsz %u", l->default_block_size); + } + } + + // extract the total number of samples from stts + if (!strcmp(type, "stts") && bytes > len) { + u32_t i; + u8_t *ptr = streambuf->readp + 12; + u32_t entries = unpackN((u32_t *)ptr); + ptr += 4; + for (i = 0; i < entries; ++i) { + u32_t count = unpackN((u32_t *)ptr); + u32_t size = unpackN((u32_t *)(ptr + 4)); + l->sttssamples += count * size; + ptr += 8; + } + LOG_DEBUG("total number of samples contained in stts: " FMT_u64, l->sttssamples); + } + + // stash sample to chunk info, assume it comes before stco + if (!strcmp(type, "stsc") && bytes > len && !l->chunkinfo) { + l->stsc = malloc(len - 12); + if (l->stsc == NULL) { + LOG_WARN("malloc fail"); + return -1; + } + memcpy(l->stsc, streambuf->readp + 12, len - 12); + } + + // build offsets table from stco and stored stsc + if (!strcmp(type, "stco") && bytes > len && l->play == l->trak) { + u32_t i; + // extract chunk offsets + u8_t *ptr = streambuf->readp + 12; + u32_t entries = unpackN((u32_t *)ptr); + ptr += 4; + l->chunkinfo = malloc(sizeof(struct chunk_table) * (entries + 1)); + if (l->chunkinfo == NULL) { + LOG_WARN("malloc fail"); + return -1; + } + for (i = 0; i < entries; ++i) { + l->chunkinfo[i].offset = unpackN((u32_t *)ptr); + l->chunkinfo[i].sample = 0; + ptr += 4; + } + l->chunkinfo[i].sample = 0; + l->chunkinfo[i].offset = 0; + // fill in first sample id for each chunk from stored stsc + if (l->stsc) { + u32_t stsc_entries = unpackN((u32_t *)l->stsc); + u32_t sample = 0; + u32_t last = 0, last_samples = 0; + u8_t *ptr = (u8_t *)l->stsc + 4; + while (stsc_entries--) { + u32_t first = unpackN((u32_t *)ptr); + u32_t samples = unpackN((u32_t *)(ptr + 4)); + if (last) { + for (i = last - 1; i < first - 1; ++i) { + l->chunkinfo[i].sample = sample; + sample += last_samples; + } + } + if (stsc_entries == 0) { + for (i = first - 1; i < entries; ++i) { + l->chunkinfo[i].sample = sample; + sample += samples; + } + } + last = first; + last_samples = samples; + ptr += 12; + } + free(l->stsc); + l->stsc = NULL; + } + } + + // found media data, advance to start of first chunk and return + if (!strcmp(type, "mdat")) { + _buf_inc_readp(streambuf, 8); + l->pos += 8; + bytes -= 8; + if (l->play) { + LOG_DEBUG("type: mdat len: %u pos: %u", len, l->pos); + if (l->chunkinfo && l->chunkinfo[0].offset > l->pos) { + u32_t skip = l->chunkinfo[0].offset - l->pos; + LOG_DEBUG("skipping: %u", skip); + if (skip <= bytes) { + _buf_inc_readp(streambuf, skip); + l->pos += skip; + } else { + l->consume = skip; + } + } + l->sample = l->nextchunk = 1; + l->block_index = 0; + return 1; + } else { + LOG_DEBUG("type: mdat len: %u, no playable track found", len); + return -1; + } + } + + // parse key-value atoms within ilst ---- entries to get encoder padding within iTunSMPB entry for gapless + if (!strcmp(type, "----") && bytes > len) { + u8_t *ptr = streambuf->readp + 8; + u32_t remain = len - 8, size; + if (!memcmp(ptr + 4, "mean", 4) && (size = unpackN((u32_t *)ptr)) < remain) { + ptr += size; remain -= size; + } + if (!memcmp(ptr + 4, "name", 4) && (size = unpackN((u32_t *)ptr)) < remain && !memcmp(ptr + 12, "iTunSMPB", 8)) { + ptr += size; remain -= size; + } + if (!memcmp(ptr + 4, "data", 4) && remain > 16 + 48) { + // data is stored as hex strings: 0 start end samples + u32_t b, c; u64_t d; + if (sscanf((const char *)(ptr + 16), "%x %x %x " FMT_x64, &b, &b, &c, &d) == 4) { + LOG_DEBUG("iTunSMPB start: %u end: %u samples: " FMT_u64, b, c, d); + if (l->sttssamples && l->sttssamples < b + c + d) { + LOG_DEBUG("reducing samples as stts count is less"); + d = l->sttssamples - (b + c); + } + l->skip = b; + l->samples = d; + } + } + } + + // default to consuming entire box + consume = len; + + // read into these boxes so reduce consume + if (!strcmp(type, "moov") || !strcmp(type, "trak") || !strcmp(type, "mdia") || !strcmp(type, "minf") || !strcmp(type, "stbl") || + !strcmp(type, "udta") || !strcmp(type, "ilst")) { + consume = 8; + } + // special cases which mix mix data in the enclosing box which we want to read into + if (!strcmp(type, "stsd")) consume = 16; + if (!strcmp(type, "mp4a")) consume = 36; + if (!strcmp(type, "meta")) consume = 12; + + // consume rest of box if it has been parsed (all in the buffer) or is not one we want to parse + if (bytes >= consume) { + LOG_DEBUG("type: %s len: %u consume: %u", type, len, consume); + _buf_inc_readp(streambuf, consume); + l->pos += consume; + bytes -= consume; + } else if ( !(!strcmp(type, "esds") || !strcmp(type, "stts") || !strcmp(type, "stsc") || + !strcmp(type, "stsz") || !strcmp(type, "stco") || !strcmp(type, "----")) ) { + LOG_DEBUG("type: %s len: %u consume: %u - partial consume: %u", type, len, consume, bytes); + _buf_inc_readp(streambuf, bytes); + l->pos += bytes; + l->consume = consume - bytes; + break; + } else { + break; + } + } + + return 0; +} + +static decode_state alac_decode(void) { + size_t bytes; + bool endstream; + u8_t *iptr; + u32_t frames, block_size; + + LOCK_S; + + // data not reached yet + if (l->consume) { + u32_t consume = min(l->consume, _buf_used(streambuf)); + LOG_DEBUG("consume: %u of %u", consume, l->consume); + _buf_inc_readp(streambuf, consume); + l->pos += consume; + l->consume -= consume; + UNLOCK_S; + return DECODE_RUNNING; + } + + if (decode.new_stream) { + int found = 0; + + // mp4 - read header + found = read_mp4_header(); + + if (found == 1) { + bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); + + LOG_INFO("setting track_start"); + LOCK_O_not_direct; + + output.next_sample_rate = decode_newstream(l->sample_rate, output.supported_rates); + output.track_start = outputbuf->writep; + if (output.fade_mode) _checkfade(true); + decode.new_stream = false; + + UNLOCK_O_not_direct; + } else if (found == -1) { + LOG_WARN("[%p]: error reading stream header"); + UNLOCK_S; + return DECODE_ERROR; + } else { + // not finished header parsing come back next time + UNLOCK_S; + return DECODE_RUNNING; + } + } + + bytes = _buf_used(streambuf); + block_size = l->default_block_size ? l->default_block_size : l->block_size[l->block_index]; + + // stream terminated + if (stream.state <= DISCONNECT && (bytes == 0 || block_size == 0)) { + UNLOCK_S; + LOG_DEBUG("end of stream"); + return DECODE_COMPLETE; + } + + // enough data for coding + if (bytes < block_size) { + UNLOCK_S; + return DECODE_RUNNING; + } else if (block_size != l->default_block_size) l->block_index++; + + bytes = min(bytes, _buf_cont_read(streambuf)); + + // need to create a buffer with contiguous data + if (bytes < block_size) { + u8_t *buffer = malloc(block_size); + memcpy(buffer, streambuf->readp, bytes); + memcpy(buffer + bytes, streambuf->buf, block_size - bytes); + iptr = buffer; + } else iptr = streambuf->readp; + + if (!alac_to_pcm(l->decoder, iptr, l->writebuf, 2, &frames)) { + LOG_ERROR("decode error"); + UNLOCK_S; + return DECODE_ERROR; + } + + // and free it + if (bytes < block_size) free(iptr); + + LOG_SDEBUG("block of %u bytes (%u frames)", block_size, frames); + + endstream = false; + // mp4 end of chunk - skip to next offset + if (l->chunkinfo && l->chunkinfo[l->nextchunk].offset && l->sample++ == l->chunkinfo[l->nextchunk].sample) { + if (l->chunkinfo[l->nextchunk].offset > l->pos) { + u32_t skip = l->chunkinfo[l->nextchunk].offset - l->pos; + if (_buf_used(streambuf) >= skip) { + _buf_inc_readp(streambuf, skip); + l->pos += skip; + } else { + l->consume = skip; + } + l->nextchunk++; + } else { + LOG_ERROR("error: need to skip backwards!"); + endstream = true; + } + // mp4 when not at end of chunk + } else if (frames) { + _buf_inc_readp(streambuf, block_size); + l->pos += block_size; + } else { + endstream = true; + } + + UNLOCK_S; + + if (endstream) { + LOG_WARN("unable to decode further"); + return DECODE_ERROR; + } + + // now point at the beginning of decoded samples + iptr = l->writebuf; + + if (l->skip) { + u32_t skip; + if (l->empty) { + l->empty = false; + l->skip -= frames; + LOG_DEBUG("gapless: first frame empty, skipped %u frames at start", frames); + } + skip = min(frames, l->skip); + LOG_DEBUG("gapless: skipping %u frames at start", skip); + frames -= skip; + l->skip -= skip; + iptr += skip * l->channels * l->sample_size; + } + + if (l->samples) { + if (l->samples < frames) { + LOG_DEBUG("gapless: trimming %u frames from end", frames - l->samples); + frames = (u32_t) l->samples; + } + l->samples -= frames; + } + + LOCK_O_direct; + + while (frames > 0) { + size_t f, count; + s32_t *optr; + + IF_DIRECT( + f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME); + optr = (s32_t *)outputbuf->writep; + ); + IF_PROCESS( + f = min(frames, process.max_in_frames - process.in_frames); + optr = (s32_t *)((u8_t *) process.inbuf + process.in_frames * BYTES_PER_FRAME); + ); + + f = min(f, frames); + count = f; + + if (l->sample_size == 8) { + while (count--) { + *optr++ = (*(u32_t*) iptr) << 24; + *optr++ = (*(u32_t*) (iptr + 1)) << 24; + iptr += 2; + } + } else if (l->sample_size == 16) { + while (count--) { + *optr++ = (*(u32_t*) iptr) << 16; + *optr++ = (*(u32_t*) (iptr + 2)) << 16; + iptr += 4; + } + } else if (l->sample_size == 24) { + while (count--) { + *optr++ = (*(u32_t*) iptr) << 8; + *optr++ = (*(u32_t*) (iptr + 3)) << 8; + iptr += 6; + } + } else if (l->sample_size == 32) { + while (count--) { + *optr++ = (*(u32_t*) iptr); + *optr++ = (*(u32_t*) (iptr + 4)); + iptr += 8; + } + } else { + LOG_ERROR("unsupported bits per sample: %u", l->sample_size); + } + + frames -= f; + + IF_DIRECT( + _buf_inc_writep(outputbuf, f * BYTES_PER_FRAME); + ); + IF_PROCESS( + process.in_frames = f; + // called only if there is enough space in process buffer + if (frames) LOG_ERROR("unhandled case"); + ); + } + + UNLOCK_O_direct; + + return DECODE_RUNNING; +} + +static void alac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { + if (l->decoder) alac_delete_decoder(l->decoder); + else l->writebuf = malloc(BLOCK_SIZE * 2); + + if (l->chunkinfo) free(l->chunkinfo); + if (l->block_size) free(l->block_size); + if (l->stsc) free(l->stsc); + l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL; + l->skip = 0; + l->samples = l->sttssamples = 0; + l->empty = false; + l->pos = l->consume = l->sample = l->nextchunk = 0; +} + +static void alac_close(void) { + if (l->decoder) alac_delete_decoder(l->decoder); + if (l->chunkinfo) free(l->chunkinfo); + if (l->block_size) free(l->block_size); + if (l->stsc) free(l->stsc); + l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL; + free(l->writebuf); +} + +struct codec *register_alac(void) { + static struct codec ret = { + 'l', // id + "alc", // types + MIN_READ, // min read + MIN_SPACE, // min space assuming a ratio of 2 + alac_open, // open + alac_close, // close + alac_decode, // decode + }; + + l = malloc(sizeof(struct alac)); + if (!l) { + return NULL; + } + + l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL; + + LOG_INFO("using alac to decode alc"); + return &ret; +} diff --git a/main/component.mk b/main/component.mk index 5ecbdcfb..a5f66381 100644 --- a/main/component.mk +++ b/main/component.mk @@ -2,10 +2,12 @@ # "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO \ +CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO -DTREMOR_ONLY \ -I$(COMPONENT_PATH)/../components/codecs/inc \ -I$(COMPONENT_PATH)/../components/codecs/inc/mad \ - -I$(COMPONENT_PATH)/../components/codecs/inc/faad2 + -I$(COMPONENT_PATH)/../components/codecs/inc/faad2 \ + -I$(COMPONENT_PATH)/../components/codecs/inc/alac \ + -I$(COMPONENT_PATH)/../components/codecs/inc/vorbis LDFLAGS += -s diff --git a/main/decode.c b/main/decode.c index f8751025..916c036b 100644 --- a/main/decode.c +++ b/main/decode.c @@ -54,7 +54,6 @@ static bool running = true; #endif static void *decode_thread() { - while (running) { size_t bytes, space, min_space; @@ -168,6 +167,9 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_ff("wma")); #endif */ + if (!strstr(exclude_codecs, "alac") && (!include_codecs || (order_codecs = strstr(include_codecs, "alac")))) + sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_alac()); + #ifndef NO_FAAD if (!strstr(exclude_codecs, "aac") && (!include_codecs || (order_codecs = strstr(include_codecs, "aac")))) sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_faad()); diff --git a/main/squeezelite.h b/main/squeezelite.h index 4df48563..b6d19f1d 100644 --- a/main/squeezelite.h +++ b/main/squeezelite.h @@ -755,6 +755,7 @@ struct codec *register_mpg(void); struct codec *register_vorbis(void); struct codec *register_faad(void); struct codec *register_dsd(void); +struct codec *register_alac(void); struct codec *register_ff(const char *codec); //gpio.c diff --git a/main/vorbis.c b/main/vorbis.c index 892a7337..67ea6f47 100644 --- a/main/vorbis.c +++ b/main/vorbis.c @@ -28,7 +28,11 @@ // tremor's OggVorbis_File struct is normally smaller so this is ok, but padding added to malloc in case it is bigger #define OV_EXCLUDE_STATIC_CALLBACKS +#ifdef TREMOR_ONLY +#include +#else #include +#endif struct vorbis { OggVorbis_File *vf; @@ -183,7 +187,9 @@ static decode_state vorbis_decode(void) { ); // write the decoded frames into outputbuf even though they are 16 bits per sample, then unpack them -#if 0 +#ifdef TREMOR_ONLY + n = OV(v, read, v->vf, (char *)write_buf, bytes, &s); +#else if (!TREMOR(v)) { #if SL_LITTLE_ENDIAN n = OV(v, read, v->vf, (char *)write_buf, bytes, 0, 2, 1, &s); @@ -196,7 +202,6 @@ static decode_state vorbis_decode(void) { #endif } #endif - n = OV(v, read, v->vf, (char *)write_buf, bytes, &s); if (n > 0) { @@ -315,8 +320,8 @@ struct codec *register_vorbis(void) { static struct codec ret = { 'o', // id "ogg", // types - 4096, // min read - 40960, // min space + 2048, // min read + 20480, // min space vorbis_open, // open vorbis_close, // close vorbis_decode,// decode