diff --git a/README.md b/README.md index f95776d8..36b29bc5 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,15 @@ Adding squeezelite #pragma GCC optimize ("O0") #pragma GCC pop_options - libflac can use espressif's version + - vorbis + - set SPIRAM_MALLOC_ALWAYSINTERNAL to 2048 as it consumes a lot of 8K blocks and uses all internal memory - when no memoru, WiFI chip fails - set IDF_PATH=/home/esp-idf - set ESPPORT=COM9 - change \components\partition_table\partitions_singleapp.csv to 2M instead of 1M (or more) - change flash's size in serial flash config to 16M - change main stack size to 8000 as well (for app_main which is slimproto) - use old "make" environment no CMake + # Wifi SCAN Example diff --git a/components/codecs/component.mk b/components/codecs/component.mk index 546d04fa..b5966e79 100644 --- a/components/codecs/component.mk +++ b/components/codecs/component.mk @@ -2,4 +2,18 @@ # "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -COMPONENT_ADD_LDFLAGS=$(COMPONENT_PATH)/lib/libmad.a $(COMPONENT_PATH)/lib/libesp-flac.a $(COMPONENT_PATH)/lib/libfaad.a -l$(COMPONENT_NAME) +COMPONENT_ADD_LDFLAGS=-l$(COMPONENT_NAME) \ + $(COMPONENT_PATH)/lib/libmad.a \ + $(COMPONENT_PATH)/lib/libesp-flac.a \ + $(COMPONENT_PATH)/lib/libfaad.a \ + $(COMPONENT_PATH)/lib/libvorbisidec.a \ + $(COMPONENT_PATH)/lib/libogg.a + + #$(COMPONENT_PATH)/lib/libvorbisidec.a + #$(COMPONENT_PATH)/lib/libogg.a + #$(COMPONENT_PATH)/lib/libesp-tremor.a + #$(COMPONENT_PATH)/lib/libesp-ogg-container.a + + + + diff --git a/components/codecs/inc/ogg/config_types.h b/components/codecs/inc/ogg/config_types.h new file mode 100644 index 00000000..4b00047a --- /dev/null +++ b/components/codecs/inc/ogg/config_types.h @@ -0,0 +1,25 @@ +#ifndef __CONFIG_TYPES_H__ +#define __CONFIG_TYPES_H__ + +/* these are filled in by configure */ +#define INCLUDE_INTTYPES_H 1 +#define INCLUDE_STDINT_H 1 +#define INCLUDE_SYS_TYPES_H 1 + +#if INCLUDE_INTTYPES_H +# include +#endif +#if INCLUDE_STDINT_H +# include +#endif +#if INCLUDE_SYS_TYPES_H +# include +#endif + +typedef int16_t ogg_int16_t; +typedef uint16_t ogg_uint16_t; +typedef int32_t ogg_int32_t; +typedef uint32_t ogg_uint32_t; +typedef int64_t ogg_int64_t; + +#endif diff --git a/components/codecs/inc/ogg/ogg.h b/components/codecs/inc/ogg/ogg.h new file mode 100644 index 00000000..7609fc24 --- /dev/null +++ b/components/codecs/inc/ogg/ogg.h @@ -0,0 +1,210 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: toplevel libogg include + last mod: $Id$ + + ********************************************************************/ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + void *iov_base; + size_t iov_len; +} ogg_iovec_t; + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern int oggpack_writecheck(oggpack_buffer *b); +extern void oggpack_writetrunc(oggpack_buffer *b,long bits); +extern void oggpack_writealign(oggpack_buffer *b); +extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); + +extern void oggpackB_writeinit(oggpack_buffer *b); +extern int oggpackB_writecheck(oggpack_buffer *b); +extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); +extern void oggpackB_writealign(oggpack_buffer *b); +extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpackB_reset(oggpack_buffer *b); +extern void oggpackB_writeclear(oggpack_buffer *b); +extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpackB_look(oggpack_buffer *b,int bits); +extern long oggpackB_look1(oggpack_buffer *b); +extern void oggpackB_adv(oggpack_buffer *b,int bits); +extern void oggpackB_adv1(oggpack_buffer *b); +extern long oggpackB_read(oggpack_buffer *b,int bits); +extern long oggpackB_read1(oggpack_buffer *b); +extern long oggpackB_bytes(oggpack_buffer *b); +extern long oggpackB_bits(oggpack_buffer *b); +extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, + int count, long e_o_s, ogg_int64_t granulepos); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_check(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); +extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_check(ogg_stream_state *os); +extern int ogg_stream_eos(ogg_stream_state *os); + +extern void ogg_page_checksum_set(ogg_page *og); + +extern int ogg_page_version(const ogg_page *og); +extern int ogg_page_continued(const ogg_page *og); +extern int ogg_page_bos(const ogg_page *og); +extern int ogg_page_eos(const ogg_page *og); +extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); +extern int ogg_page_serialno(const ogg_page *og); +extern long ogg_page_pageno(const ogg_page *og); +extern int ogg_page_packets(const ogg_page *og); + +extern void ogg_packet_clear(ogg_packet *op); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/components/codecs/inc/ogg/os_types.h b/components/codecs/inc/ogg/os_types.h new file mode 100644 index 00000000..b8f56308 --- /dev/null +++ b/components/codecs/inc/ogg/os_types.h @@ -0,0 +1,148 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id$ + + ********************************************************************/ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _ogg_malloc malloc +#define _ogg_calloc calloc +#define _ogg_realloc realloc +#define _ogg_free free + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# elif defined(__MINGW32__) +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; +# elif defined(__MWERKS__) + typedef long long ogg_int64_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# else + /* MSVC/Borland */ + typedef __int64 ogg_int64_t; + typedef __int32 ogg_int32_t; + typedef unsigned __int32 ogg_uint32_t; + typedef __int16 ogg_int16_t; + typedef unsigned __int16 ogg_uint16_t; +# endif +# endif + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + +#elif defined(__HAIKU__) + + /* Haiku */ +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short ogg_int16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef long ogg_int64_t; + typedef int ogg_int32_t; + typedef unsigned ogg_uint32_t; + typedef short ogg_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + +#elif defined(__TMS320C6X__) + + /* TI C64x compiler */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + +#else + +# include + +#endif + +#endif /* _OS_TYPES_H */ diff --git a/components/codecs/inc/vorbis/ivorbiscodec.h b/components/codecs/inc/vorbis/ivorbiscodec.h new file mode 100644 index 00000000..379872a7 --- /dev/null +++ b/components/codecs/inc/vorbis/ivorbiscodec.h @@ -0,0 +1,203 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * + * * + ******************************************************************** + + function: libvorbis codec headers + + ********************************************************************/ + +#ifndef _vorbis_codec_h_ +#define _vorbis_codec_h_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include + +typedef struct vorbis_info{ + int version; + int channels; + long rate; + + /* The below bitrate declarations are *hints*. + Combinations of the three values carry the following implications: + + all three set to the same value: + implies a fixed rate bitstream + only nominal set: + implies a VBR stream that averages the nominal bitrate. No hard + upper/lower limit + upper and or lower set: + implies a VBR bitstream that obeys the bitrate limits. nominal + may also be set to give a nominal rate. + none set: + the coder does not care to speculate. + */ + + long bitrate_upper; + long bitrate_nominal; + long bitrate_lower; + long bitrate_window; + + void *codec_setup; +} vorbis_info; + +/* vorbis_dsp_state buffers the current vorbis audio + analysis/synthesis state. The DSP state belongs to a specific + logical bitstream ****************************************************/ +typedef struct vorbis_dsp_state{ + int analysisp; + vorbis_info *vi; + + ogg_int32_t **pcm; + ogg_int32_t **pcmret; + int pcm_storage; + int pcm_current; + int pcm_returned; + + int preextrapolate; + int eofflag; + + long lW; + long W; + long nW; + long centerW; + + ogg_int64_t granulepos; + ogg_int64_t sequence; + + void *backend_state; +} vorbis_dsp_state; + +typedef struct vorbis_block{ + /* necessary stream state for linking to the framing abstraction */ + ogg_int32_t **pcm; /* this is a pointer into local storage */ + oggpack_buffer opb; + + long lW; + long W; + long nW; + int pcmend; + int mode; + + int eofflag; + ogg_int64_t granulepos; + ogg_int64_t sequence; + vorbis_dsp_state *vd; /* For read-only access of configuration */ + + /* local storage to avoid remallocing; it's up to the mapping to + structure it */ + void *localstore; + long localtop; + long localalloc; + long totaluse; + struct alloc_chain *reap; + +} vorbis_block; + +/* vorbis_block is a single block of data to be processed as part of +the analysis/synthesis stream; it belongs to a specific logical +bitstream, but is independant from other vorbis_blocks belonging to +that logical bitstream. *************************************************/ + +struct alloc_chain{ + void *ptr; + struct alloc_chain *next; +}; + +/* vorbis_info contains all the setup information specific to the + specific compression/decompression mode in progress (eg, + psychoacoustic settings, channel setup, options, codebook + etc). vorbis_info and substructures are in backends.h. +*********************************************************************/ + +/* the comments are not part of vorbis_info so that vorbis_info can be + static storage */ +typedef struct vorbis_comment{ + /* unlimited user comment fields. libvorbis writes 'libvorbis' + whatever vendor is set to in encode */ + char **user_comments; + int *comment_lengths; + int comments; + char *vendor; + +} vorbis_comment; + + +/* libvorbis encodes in two abstraction layers; first we perform DSP + and produce a packet (see docs/analysis.txt). The packet is then + coded into a framed OggSquish bitstream by the second layer (see + docs/framing.txt). Decode is the reverse process; we sync/frame + the bitstream and extract individual packets, then decode the + packet back into PCM audio. + + The extra framing/packetizing is used in streaming formats, such as + files. Over the net (such as with UDP), the framing and + packetization aren't necessary as they're provided by the transport + and the streaming layer is not used */ + +/* Vorbis PRIMITIVES: general ***************************************/ + +extern void vorbis_info_init(vorbis_info *vi); +extern void vorbis_info_clear(vorbis_info *vi); +extern int vorbis_info_blocksize(vorbis_info *vi,int zo); +extern void vorbis_comment_init(vorbis_comment *vc); +extern void vorbis_comment_add(vorbis_comment *vc, char *comment); +extern void vorbis_comment_add_tag(vorbis_comment *vc, + char *tag, char *contents); +extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count); +extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag); +extern void vorbis_comment_clear(vorbis_comment *vc); + +extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); +extern int vorbis_block_clear(vorbis_block *vb); +extern void vorbis_dsp_clear(vorbis_dsp_state *v); + +/* Vorbis PRIMITIVES: synthesis layer *******************************/ +extern int vorbis_synthesis_idheader(ogg_packet *op); +extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, + ogg_packet *op); + +extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); +extern int vorbis_synthesis_restart(vorbis_dsp_state *v); +extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); +extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op); +extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); +extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm); +extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); +extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); + +/* Vorbis ERRORS and return codes ***********************************/ + +#define OV_FALSE -1 +#define OV_EOF -2 +#define OV_HOLE -3 + +#define OV_EREAD -128 +#define OV_EFAULT -129 +#define OV_EIMPL -130 +#define OV_EINVAL -131 +#define OV_ENOTVORBIS -132 +#define OV_EBADHEADER -133 +#define OV_EVERSION -134 +#define OV_ENOTAUDIO -135 +#define OV_EBADPACKET -136 +#define OV_EBADLINK -137 +#define OV_ENOSEEK -138 + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/components/codecs/inc/vorbis/vorbisfile.h b/components/codecs/inc/vorbis/vorbisfile.h new file mode 100644 index 00000000..7e9bd5b0 --- /dev/null +++ b/components/codecs/inc/vorbis/vorbisfile.h @@ -0,0 +1,130 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + + ********************************************************************/ + +#ifndef _OV_FILE_H_ +#define _OV_FILE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#include +#include "ivorbiscodec.h" + +#define CHUNKSIZE 65535 +#define READSIZE 1024 +/* The function prototypes for the callbacks are basically the same as for + * the stdio functions fread, fseek, fclose, ftell. + * The one difference is that the FILE * arguments have been replaced with + * a void * - this is to be used as a pointer to whatever internal data these + * functions might need. In the stdio case, it's just a FILE * cast to a void * + * + * If you use other functions, check the docs for these functions and return + * the right values. For seek_func(), you *MUST* return -1 if the stream is + * unseekable + */ +typedef struct { + size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); + int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); + int (*close_func) (void *datasource); + long (*tell_func) (void *datasource); +} ov_callbacks; + +#define NOTOPEN 0 +#define PARTOPEN 1 +#define OPENED 2 +#define STREAMSET 3 +#define INITSET 4 + +typedef struct OggVorbis_File { + void *datasource; /* Pointer to a FILE *, etc. */ + int seekable; + ogg_int64_t offset; + ogg_int64_t end; + ogg_sync_state oy; + + /* If the FILE handle isn't seekable (eg, a pipe), only the current + stream appears */ + int links; + ogg_int64_t *offsets; + ogg_int64_t *dataoffsets; + ogg_uint32_t *serialnos; + ogg_int64_t *pcmlengths; + vorbis_info *vi; + vorbis_comment *vc; + + /* Decoding working state local storage */ + ogg_int64_t pcm_offset; + int ready_state; + ogg_uint32_t current_serialno; + int current_link; + + ogg_int64_t bittrack; + ogg_int64_t samptrack; + + ogg_stream_state os; /* take physical pages, weld into a logical + stream of packets */ + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + ov_callbacks callbacks; + +} OggVorbis_File; + +extern int ov_clear(OggVorbis_File *vf); +extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); +extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf, + const char *initial, long ibytes, ov_callbacks callbacks); + +extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); +extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf, + const char *initial, long ibytes, ov_callbacks callbacks); +extern int ov_test_open(OggVorbis_File *vf); + +extern long ov_bitrate(OggVorbis_File *vf,int i); +extern long ov_bitrate_instant(OggVorbis_File *vf); +extern long ov_streams(OggVorbis_File *vf); +extern long ov_seekable(OggVorbis_File *vf); +extern long ov_serialnumber(OggVorbis_File *vf,int i); + +extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i); +extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i); +extern ogg_int64_t ov_time_total(OggVorbis_File *vf,int i); + +extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_time_seek(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t pos); + +extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf); +extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf); +extern ogg_int64_t ov_time_tell(OggVorbis_File *vf); + +extern vorbis_info *ov_info(OggVorbis_File *vf,int link); +extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); + +extern long ov_read(OggVorbis_File *vf,char *buffer,int length, + int *bitstream); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif + diff --git a/components/codecs/lib/libesp-ogg-container.a b/components/codecs/lib/libesp-ogg-container.a new file mode 100644 index 00000000..40ce6cab Binary files /dev/null and b/components/codecs/lib/libesp-ogg-container.a differ diff --git a/components/codecs/lib/libesp-tremor.a b/components/codecs/lib/libesp-tremor.a new file mode 100644 index 00000000..4cb36e74 Binary files /dev/null and b/components/codecs/lib/libesp-tremor.a differ diff --git a/components/codecs/lib/libesp_processing.a b/components/codecs/lib/libesp_processing.a new file mode 100644 index 00000000..1d92b644 Binary files /dev/null and b/components/codecs/lib/libesp_processing.a differ diff --git a/components/codecs/lib/libmad.a b/components/codecs/lib/libmad.a index a97022a2..46cba07e 100644 Binary files a/components/codecs/lib/libmad.a and b/components/codecs/lib/libmad.a differ diff --git a/components/codecs/lib/libogg.a b/components/codecs/lib/libogg.a new file mode 100644 index 00000000..725272c3 Binary files /dev/null and b/components/codecs/lib/libogg.a differ diff --git a/components/codecs/lib/libvorbisidec.a b/components/codecs/lib/libvorbisidec.a new file mode 100644 index 00000000..3784e8bd Binary files /dev/null and b/components/codecs/lib/libvorbisidec.a differ diff --git a/main/decode.c b/main/decode.c index 4ef92ca1..f8751025 100644 --- a/main/decode.c +++ b/main/decode.c @@ -54,6 +54,7 @@ static bool running = true; #endif static void *decode_thread() { + while (running) { size_t bytes, space, min_space; @@ -171,10 +172,8 @@ void decode_init(log_level level, const char *include_codecs, const char *exclud if (!strstr(exclude_codecs, "aac") && (!include_codecs || (order_codecs = strstr(include_codecs, "aac")))) sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_faad()); #endif -/* if (!strstr(exclude_codecs, "ogg") && (!include_codecs || (order_codecs = strstr(include_codecs, "ogg")))) sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_vorbis()); -*/ if (!strstr(exclude_codecs, "flac") && (!include_codecs || (order_codecs = strstr(include_codecs, "flac")))) sort_codecs((include_codecs ? order_codecs - include_codecs : i), register_flac()); diff --git a/main/squeezelite.h b/main/squeezelite.h index 1ddf6f8f..4df48563 100644 --- a/main/squeezelite.h +++ b/main/squeezelite.h @@ -280,8 +280,12 @@ #include #endif /* SUN */ +#ifndef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 256 +#endif + #define STREAM_THREAD_STACK_SIZE 8 * 1024 -#define DECODE_THREAD_STACK_SIZE 32 * 1024 +#define DECODE_THREAD_STACK_SIZE 20 * 1024 #define OUTPUT_THREAD_STACK_SIZE 8 * 1024 #define IR_THREAD_STACK_SIZE 8 * 1024 #if !OSX diff --git a/main/vorbis.c b/main/vorbis.c new file mode 100644 index 00000000..892a7337 --- /dev/null +++ b/main/vorbis.c @@ -0,0 +1,339 @@ +/* + * Squeezelite - lightweight headless squeezebox emulator + * + * (c) Adrian Smith 2012-2015, triode1@btinternet.com + * Ralph Irving 2015-2017, ralph_irving@hotmail.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" + +// automatically select between floating point (preferred) and fixed point libraries: +// NOTE: works with Tremor version here: http://svn.xiph.org/trunk/Tremor, not vorbisidec.1.0.2 currently in ubuntu + +// we take common definations from even though we can use tremor at run time +// 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 + +#include + +struct vorbis { + OggVorbis_File *vf; + bool opened; +#if !LINKALL + // vorbis symbols to be dynamically loaded - from either vorbisfile or vorbisidec (tremor) version of library + vorbis_info *(* ov_info)(OggVorbis_File *vf, int link); + int (* ov_clear)(OggVorbis_File *vf); + long (* ov_read)(OggVorbis_File *vf, char *buffer, int length, int bigendianp, int word, int sgned, int *bitstream); + long (* ov_read_tremor)(OggVorbis_File *vf, char *buffer, int length, int *bitstream); + int (* ov_open_callbacks)(void *datasource, OggVorbis_File *vf, const char *initial, long ibytes, ov_callbacks callbacks); +#endif +}; + +static struct vorbis *v; + +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 + +#if LINKALL +#define OV(h, fn, ...) (ov_ ## fn)(__VA_ARGS__) +#define TREMOR(h) 0 +#if !WIN +extern int ov_read_tremor(); // needed to enable compilation, not linked +#endif +#else +#define OV(h, fn, ...) (h)->ov_##fn(__VA_ARGS__) +#define TREMOR(h) (h)->ov_read_tremor +#endif + +// called with mutex locked within vorbis_decode to avoid locking O before S +static size_t _read_cb(void *ptr, size_t size, size_t nmemb, void *datasource) { + size_t bytes; + + bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); + bytes = min(bytes, size * nmemb); + + memcpy(ptr, streambuf->readp, bytes); + _buf_inc_readp(streambuf, bytes); + + return bytes / size; +} + +// these are needed for older versions of tremor, later versions and libvorbis allow NULL to be used +static int _seek_cb(void *datasource, ogg_int64_t offset, int whence) { return -1; } +static int _close_cb(void *datasource) { return 0; } +static long _tell_cb(void *datasource) { return 0; } + +static decode_state vorbis_decode(void) { + static int channels; + bool end; + frames_t frames; + int bytes, s, n; + u8_t *write_buf; + + LOCK_S; + LOCK_O_direct; + end = (stream.state <= DISCONNECT); + + IF_DIRECT( + frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; + ); + IF_PROCESS( + frames = process.max_in_frames; + ); + + if (!frames && end) { + UNLOCK_O_direct; + UNLOCK_S; + return DECODE_COMPLETE; + } + + if (decode.new_stream) { + ov_callbacks cbs; + int err; + struct vorbis_info *info; + + cbs.read_func = _read_cb; + + if (TREMOR(v)) { + cbs.seek_func = _seek_cb; cbs.close_func = _close_cb; cbs.tell_func = _tell_cb; + } else { + cbs.seek_func = NULL; cbs.close_func = NULL; cbs.tell_func = NULL; + } + + if ((err = OV(v, open_callbacks, streambuf, v->vf, NULL, 0, cbs)) < 0) { + LOG_WARN("open_callbacks error: %d", err); + UNLOCK_O_direct; + UNLOCK_S; + return DECODE_COMPLETE; + } + v->opened = true; + + info = OV(v, info, v->vf, -1); + + LOG_INFO("setting track_start"); + LOCK_O_not_direct; + output.next_sample_rate = decode_newstream(info->rate, output.supported_rates); + IF_DSD( output.next_fmt = PCM; ) + output.track_start = outputbuf->writep; + if (output.fade_mode) _checkfade(true); + decode.new_stream = false; + UNLOCK_O_not_direct; + + IF_PROCESS( + frames = process.max_in_frames; + ); + + channels = info->channels; + + if (channels > 2) { + LOG_WARN("too many channels: %d", channels); + UNLOCK_O_direct; + UNLOCK_S; + return DECODE_ERROR; + } + } + + bytes = frames * 2 * channels; // samples returned are 16 bits + + IF_DIRECT( + write_buf = outputbuf->writep; + ); + IF_PROCESS( + write_buf = process.inbuf; + ); + + // write the decoded frames into outputbuf even though they are 16 bits per sample, then unpack them +#if 0 + if (!TREMOR(v)) { +#if SL_LITTLE_ENDIAN + n = OV(v, read, v->vf, (char *)write_buf, bytes, 0, 2, 1, &s); +#else + n = OV(v, read, v->vf, (char *)write_buf, bytes, 1, 2, 1, &s); +#endif +#if !WIN + } else { + n = OV(v, read_tremor, v->vf, (char *)write_buf, bytes, &s); +#endif + } +#endif + n = OV(v, read, v->vf, (char *)write_buf, bytes, &s); + + if (n > 0) { + + frames_t count; + s16_t *iptr; + s32_t *optr; + + frames = n / 2 / channels; + count = frames * channels; + + // work backward to unpack samples to 4 bytes per sample + iptr = (s16_t *)write_buf + count; + optr = (s32_t *)write_buf + frames * 2; + + if (channels == 2) { + while (count--) { + *--optr = *--iptr << 16; + } + } else if (channels == 1) { + while (count--) { + *--optr = *--iptr << 16; + *--optr = *iptr << 16; + } + } + + IF_DIRECT( + _buf_inc_writep(outputbuf, frames * BYTES_PER_FRAME); + ); + IF_PROCESS( + process.in_frames = frames; + ); + + LOG_SDEBUG("wrote %u frames", frames); + + } else if (n == 0) { + + LOG_INFO("end of stream"); + UNLOCK_O_direct; + UNLOCK_S; + return DECODE_COMPLETE; + + } else if (n == OV_HOLE) { + + // recoverable hole in stream, seen when skipping + LOG_DEBUG("hole in stream"); + + } else { + + LOG_INFO("ov_read error: %d", n); + UNLOCK_O_direct; + UNLOCK_S; + return DECODE_COMPLETE; + } + + UNLOCK_O_direct; + UNLOCK_S; + + return DECODE_RUNNING; +} + +static void vorbis_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { + if (!v->vf) { + v->vf = malloc(sizeof(OggVorbis_File) + 128); // add some padding as struct size may be larger + memset(v->vf, 0, sizeof(OggVorbis_File) + 128); + } else { + if (v->opened) { + OV(v, clear, v->vf); + v->opened = false; + } + } +} + +static void vorbis_close(void) { + if (v->opened) { + OV(v, clear, v->vf); + v->opened = false; + } + free(v->vf); + v->vf = NULL; +} + +static bool load_vorbis() { +#if !LINKALL + void *handle = dlopen(LIBVORBIS, RTLD_NOW); + char *err; + bool tremor = false; + + if (!handle) { + handle = dlopen(LIBTREMOR, RTLD_NOW); + if (handle) { + tremor = true; + } else { + LOG_INFO("dlerror: %s", dlerror()); + return false; + } + } + + v->ov_read = tremor ? NULL : dlsym(handle, "ov_read"); + v->ov_read_tremor = tremor ? dlsym(handle, "ov_read") : NULL; + v->ov_info = dlsym(handle, "ov_info"); + v->ov_clear = dlsym(handle, "ov_clear"); + v->ov_open_callbacks = dlsym(handle, "ov_open_callbacks"); + + if ((err = dlerror()) != NULL) { + LOG_INFO("dlerror: %s", err); + return false; + } + + LOG_INFO("loaded %s", tremor ? LIBTREMOR : LIBVORBIS); +#endif + + return true; +} + +struct codec *register_vorbis(void) { + static struct codec ret = { + 'o', // id + "ogg", // types + 4096, // min read + 40960, // min space + vorbis_open, // open + vorbis_close, // close + vorbis_decode,// decode + }; + + v = malloc(sizeof(struct vorbis)); + if (!v) { + return NULL; + } + + v->vf = NULL; + v->opened = false; + + if (!load_vorbis()) { + return NULL; + } + + LOG_INFO("using vorbis to decode ogg"); + return &ret; +}